Tom4045
Tom4045

Reputation: 29

How can I track steps in Game Maker Studio 2 for random encounters

I am trying to make a simple RPG just for fun.

I am currently working on a random encounter system and I found this piece of code on Reddit which could be usefull;

///This code should be under your object's create event:

encounterSteps = irandom_range(10,20);

///This code should run when you take a step:

if (steps > encounterSteps) {
    steps = 0;
    encounterSteps = irandom_range(10,20);
    room_goto(rm_battle);
}

There is one problem however, this system uses a variable called "steps" and I currently don't have that variable. Now I obviously know that I need to count my steps in order for this to work, but I'm not entirely sure how I would count my steps. I am currently using the following code for movement:

var moveSpeed = 4;

if (_kLeft && !place_meeting(x - moveSpeed, y, oWall))
{
    x -= moveSpeed;
    sprite_index = sPlayerLeft;
    image_speed = 0.5;
}
    
if (_kRight && !place_meeting(x + moveSpeed, y, oWall))
{
    x += moveSpeed;
    sprite_index = sPlayerRight;
    image_speed = 0.5;
}
    
if (_kUp && !place_meeting(x, y - moveSpeed, oWall))
{
    y -= moveSpeed;
    sprite_index = sPlayerUp;
    image_speed = 0.5;
}
    
if (_kDown && !place_meeting(x, y + moveSpeed, oWall))
{
    y += moveSpeed;
    sprite_index = sPlayerDown;
    image_speed = 0.5;
}

I'm assuming I'll have to change this code to be more like a 1 step at a time system.

Now my question: How can I make a system that tracks steps OR that can generate random encounters using my current movement system?

Upvotes: 0

Views: 428

Answers (2)

Treasure Dev
Treasure Dev

Reputation: 588

Kilazur has a great approach to this but if we're looking from a game maker studio perspective then we already have some read-only variables that allow us to see what frame it's on, such as image_index. So at the very least, it's simple enough to get implemented (even if it might not be the most optimal approach). This is an approach I'd personally try using:

//--Create--//
encounterRate = irandom(30,40);
encounterSteps = 0;
// We condition lock steps so it's only counting it the one time for that cycle
stepOneCounted = false, stepTwoCounted = false, stepCountComplete = false;
//--Step--//
if (sprite_index == spr_player_walking) {
    // sprite_get_number returns real numb and not whole numb (i.e. 1-2-3 not 0-1-2-3) | also, function needs at least 1 sub img to work
    totalWalkAniFrames = sprite_get_number(sprite_index)-1;
    // Left step
    if (image_index == 3 && !stepOneCounted) { 
        encounterSteps += 1; 
        stepOneCounted = true;
    }
    // Right step
    if (image_index == 5 && !stepTwoCounted) { 
        encounterSteps += 1; 
        stepTwoCounted = true;
    }
    // Cycle completed
    if (image_index == totalWalkAniFrames && !stepCountComplete) {
        stepOneCounted = false;
        stepTwoCounted = false;
        stepCountComplete = true;
    }
    // Do this again
    if (image_index == 0) { 
        stepCountComplete = false; 
    }
}
// ...
if (encounterRate >= encounterSteps){
    // do the thing and reset the encounter rate & encounter steps
    // also, be sure to default the 'step counted' variables in case it stops in a weird spot like step one's true, but step twos false still. 
}

Lastly, be sure to adjust image index numbers based on the frames of your movement animation. A pretty simple and general solution but hopefully this helps.

Upvotes: 0

Kilazur
Kilazur

Reputation: 3188

I can't talk about the code you're using, since I don't have the context of your project. But here's a version I would use myself I believe.

First, you're going to need two variables/properties to define the current risk of encounter, and the rate of encounter.

The first one will increase when you move, and you will periodically perform a check between a random number and encounterRate. When the random number is lower than encounterRisk, start a battle and reset encounterRisk.

You could perform this check every frame, but this could be resource intensive. A better idea would be to do it in a Timer's callback function.

I don't know how your class looks, so you'll have to adapt this.

private int MoveSpeed { get; } = 4;
private Timer EncounterTimer { get; set; }
private int EncounterRisk { get; set; } = 0;
private int EncounterRate { get; set; } = 1000; // to fine tune depending on your needs

public YourClassConstructor()
{
    EncounterTimer = new System.Timers.Timer(100);
    EncounterTimer.Elapsed += CheckForEncounter;
}

public void CheckForEncounter()
{
    EncounterRisk++;
    
    // Maybe use something bigger than 0 here, otherwise there is a non-zero chance that you get 2 encounters in a row without being able to move
    var random = new Random().Next(0, EncounterRate);

    if (random < EncounterRisk)
    {
        EncounterRisk = 0;
        // start a battle
    }
}

// your moving function
public void Move()
{
    var moving = false;
    var xMoveAmount = 0;
    var yMoveAmount = 0;

    if (_kLeft && !place_meeting(x - MoveSpeed, y, oWall))
    {
        xMoveAmount -= MoveSpeed;
        sprite_index = sPlayerLeft;
        moving = true;
    }

    if (_kRight && !place_meeting(x + MoveSpeed, y, oWall))
    {
        xMoveAmount += MoveSpeed;
        sprite_index = sPlayerRight;
        moving = true;
    }

    if (_kUp && !place_meeting(x, y - MoveSpeed, oWall))
    {
        yMoveAmount -= MoveSpeed;
        sprite_index = sPlayerUp;
        moving = true;
    }

    if (_kDown && !place_meeting(x, y + MoveSpeed, oWall))
    {
        yMoveAmount += MoveSpeed;
        sprite_index = sPlayerDown;
        moving = true;
    }

    if (moving)
    {
        image_speed = 0.5; // not sure if you need to set that every frame, maybe you can put it under the following "if"
        x += xMoveAmount;
        y += yMoveAmount;

        if (!EncounterTimer.Enabled)
        {
            EncounterTimer.Enabled = true;
        }
    }
    else
    {
       EncounterTimer.Enabled = false;
    }
}

Upvotes: 1

Related Questions