Reputation: 29
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
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
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