(forgive me, I didn't quite know what to call this, as far as descriptive thread titles go)
Hey all,
I've been scratching my head at some of the challenges in building a quest system (https://www.adventuregamestudio.co.uk/forums/index.php?topic=58265.0). Before I dive back into that monstrosity, I wanted to ask a simpler question that would clean up a lot of my code.
TL;DR - Structs and Arrays are fun and very, very powerful. However, creating a new instance of a struct object that lives inside of an array forces me to do somewhat gross stuff like this:
task[1].complete
Ostensibly, it's fine as-is. If I wanted to manually make calls like that every time a task gets marked as Completed, it would work. But it's ugly, kind of goes against the concept of "Don't Repeat Yourself", and makes it difficult to reference in generic functions. It can also potentially cause off-by-one errors if, say, I somehow create tasks in a non-linear order./
So, let's say every task object has a unique identifier, like an ID. Maybe this task has an ID of 4, but it was created with an array index of [3].
How might I go about referencing this without causing an off-by-one error? Is it possible to refer to a task by a related variable, rather than the index itself? Otherwise, is there some magic index variable I can use like task[task.array_number].complete?
You can use an int variable as array index, yes. An enum will also work:
enum TaskIndex {
eTaskBecomePirate, eTaskKillLeChuck
};
You can now do
task[eTaskBecomePirate].complete = true;
The question is, how would generic functions look like? A simple example would be
void MarkTaskComplete(TaskIndex index) {
task[index].complete = true;
}
But a function like that is pretty pointless.
Hmm, that's pretty interesting. I didn't really know about enum!
I guess I've been trying to just figure out how to keep track of child objects belonging to a parent object, and manipulate their state in an external function. It seemed like setting the state of the child objects based on the altered state of the parent would be a solution to another problem I was having, and that doing some kind of generic function could serve as a catch-all.
In other words (pseudocode incoming)
if (parent_object.state = completed) {
for each child_object {
child_object.state = completed;
}
}
Or something to that effect.
You can keep an array of ints in a parent instance that stores the indices of the child objects.
Quote from: Khris on Sun 08/11/2020 23:16:29
You can keep an array of ints in a parent instance that stores the indices of the child objects.
Yeah, I had that thought too the other day, but kind of drew a blank on how to do that.
Seems like basically I'd be creating an entirely new array and then somehow assigning the whole thing to a Struct?
Say you have:
struct Parent {
int ID;
int childrenIDs[10];
int childrenCount;
};
Using an array of fixed size to keep track of instances is best done by keeping a count variable (initialized to 0).
When you need a "new" instance, you use the count as index, then simply increase it by one.
You can now write a function that adds a task:
void Parent::AddTask(String description) {
task[task_count].description = description;
task[task_count].parentID = this.ID;
// add task ID to parent's children array
this.childrenIDs[this.childrenCount] = task_count;
this.childrenCount++;
task_count++;
}
To iterate over a parent's tasks:
void Parent::SetAllTasksComplete() {
for (int i = 0; i < this.childrenCount; i++) {
task[this.childrenIDs[i]].complete = true;
}
}