2015-02-28 00:27:55 (edited by matt1211 2015-02-28 00:28:51)

Hi, I'm having a bit of trouble thinking of a way to cause enemies to die with my current setup, and was wondering if anyone had any suggestions. At this point, it works like this:
I've got a level class, with an array of enemies. Each enemy has an x, a y, and a radius. When my weapons bullet intersects the circle that is the enemy, it's health should go down. This part works, but I can't think of a way to get rid of the enemy once it's health is gone. In the past I've just been using 2d arrays to store enemies, so I could just do something like. level.enemies[this.x][this.y]=null;
That doesn't work now however, since I've just put the x and y coordinates in class methods. Any suggestions would be greatly appreciated.

Prier practice and preparation prevents piss poor performance!

2015-02-28 00:49:07

I don't understand what the difficult is if you meant that by putting the coordinates in class methods, the methods just returned the coordinates. If you still have a 2d array of enemies in your level class, you can just get the methods to return the proper x and y coordinates, as though they were just plain old properties as before.

I like to sleep, Sleep is good,
This is how I do it: Lie on a nice warm cozy bed, and dream dreams about how to rule the world!
Follow @TheGreatAthlon5 on twitter for humorous facts and game updates!
If you like my posts, thumb me up!

2015-02-28 00:55:54

Sorry. I meant properties. And, they weren't quite properties before. I had an x and a y value, but they just moved on the 2d array. So I could just go level.enemies[this.x][this.y]=null;
Or something like that. Now, because enemies are just in a 1d array, I can't do this, which is my problem.

Prier practice and preparation prevents piss poor performance!

2015-02-28 01:56:19

Hi there,

So, do you mean you determine if an enemy is dead seting its position vector = null?
I'd recommend another aproach: store all enemies in an array of enemy references, this way, you can easyly iterate the whole array and perform updating, and you can dispose with:
Enemies[2] = null;

The main game class for your game is a good place to include array members to regiser and unregister enemies, players, etc.
Hope I've understood your question.

2015-02-28 04:47:06

You have to put the enemy class in a central location from which it could be removed.  Ideas for this include an array of enemy objects or, perhaps better, a dictionary of enemy objects.  Depending on how complicated the rest of your game is, you may need to then program defensively: nothing is ever allowed to hold on to this object and must look it up from the central location.  This is most commonly done by giving the object a unique id which can never be reused, even after the object's death.  In truth, most game-related queries are things like "all enemies in this region" and thus can't be cached anyway.
the problem with strong references in complicated setups is that you might end up with weird zombie ghost enemies of crashing.  A central lookup at least reminds you "hey, this might fail".  It's the approach I'm currently using anyway.  I'm hard pressed to think of a better one.  Such might exist, somewhere, so maybe look to see what the sighted game programmers are doing.

My Blog
Twitter: @ajhicks1992

2015-02-28 06:22:25

Hi,
I'm having a similar problem in BGT. I managed to get shooting in my game, but when you fire at the enemy, it gives a runtime error:
A runtime error occurred.
File: C:\Users\EthinP\Documents\troop3\includes\enemy.bgt
On line: 33
In function: void enemy::die()
Description: Too large array size
The stack trace is:
Call stack size: 6

File: C:\Users\EthinP\Documents\troop3\includes\enemy.bgt
Line: 34 (2)
Function: void enemy::die()

File: C:\Users\EthinP\Documents\troop3\includes\enemy.bgt
Line: 23 (3)
Function: void enemy::hit(int)

File: C:\Users\EthinP\Documents\troop3\troop3.bgt
Line: 287 (1)
Function: void gameloop(level@, int)

File: C:\Users\EthinP\Documents\troop3\troop3.bgt
Line: 107 (1)
Function: void difficulty_menu(bool = false, bool = false)

File: C:\Users\EthinP\Documents\troop3\troop3.bgt
Line: 56 (1)
Function: void main_menu()

File: C:\Users\EthinP\Documents\troop3\troop3.bgt
Line: 26 (1)
Function: void main()

(The call stack gave it away. Its troop 3.)
The code of the top entry, which I'm assuming is the issue, is:
enemy@[] enemies;
//basic enemy class. Subclasses can be written later to expand and give different enemies different functions.
//The level class must also be included for the methods in this class to work.
class enemy {
    int health, speed=250, ex=0, ey=100, cycle=1;
    string soundpath;
    double[] enemies;
    timer movetimer;
  enemy(level @lvl, int h, string s, int sp) {
        this.health = h;
        this.soundpath=s;
        this.speed = sp;
        spool.destroy_all();
int maxpos = lvl.maxPosition;
        this.ex = random (0, maxpos);
    }
    enemy() {
        //no default constructor allowed.
    }
    void hit(int d) {
        this.health=this.health-d;
        if(this.health<=0) {
        this.die();
        }
        else
        {
        spool.play_1d (this.soundpath+"hit.ogg", x, ex, false, false);
        }
    }
void die ()
{
spool.play_1d (this.soundpath+"die.ogg", x, ex, false, false);
enemies.resize (enemies.length() - 1);
}
void move()
{
if(this.cycle==2)
{
this.ey=this.ey-5;
this.cycle=1;
}
else
{
this.cycle=2;
}
spool.play_extended_1d(this.soundpath+"move.ogg", x, ex, 0, 0, false, 0, 0, 100, ey+50, false);

}
}
void destroy_all_enemies()
{
enemies.resize(0);
}
Please remember that this is only an include. It does not include the required include files. the main source code does that.
Can anyone help?

"On two occasions I have been asked [by members of Parliament!]: 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out ?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question."    — Charles Babbage.
My Github

2015-02-28 15:18:49

You can only remove dead enemies from outside the class. That said, it's pretty simple:

for (uint i=0; i<enemies.length(); i++) {
  enemies[i].step();
  if(enemies[i].health<=0) {
    enemies.remove_at(i);
    i--;
  }
}
看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2015-02-28 18:43:05

Are  you saying that BGT only allows the removal of array elements from outside the instance representing that element?  I'm not sure why the code can't be abstracted into the enemies themselves, provided that they know what slot they are in the array.  I know it doesn't matter in terms of functionality, but I'm curious why you're saying it's impossible.

My Blog
Twitter: @ajhicks1992

2015-02-28 23:22:12

Okay. I now see the logical error in my assumption that this can be inside the class.  I'd suggest using a dictionary of unique enemy ids to enemies so that each enemy can remove itself without affecting the position of other enemies, as letting instances which exist in an array know about which slot they are will increase bookkeeping a lot.

My Blog
Twitter: @ajhicks1992

2015-03-01 12:43:59 (edited by Genroa 2015-03-01 12:46:35)

Exactly, a dictionary can be a good solution to store ennemies and manage them without order! smile I think this way if you erase the reference in the dictionary the object will just be garbage collected and so you have your solution. Arrays are only good to do things on the hole selection of objects which are inside it, you can't really use index to manage them

2015-03-01 18:44:54

Hi guys, thanks very much for the advice! I've never really looked into dictionaries,  but I'm beginning to think that I should. smile

Prier practice and preparation prevents piss poor performance!

2015-03-01 19:32:16

I use them for everything.  They're usually better than arrays when it comes to "hold a big collection of stuff".
the interesting thing is this.  BGT is using hashtables.  Asking "Is this in the dictionary" is a question which completes in something close to constant time.  In English, whether there's 1, 10, 1000, or 100000 items in the dictionary, "is x in the dictionary" will complete in about the same amount of time.  So too will deletion (you don't have to shift the items).  Your ram will run out before it gets even a millionth as slow as the equivalent array.
The upshot is that if you're looking for a place to make your game a hundred thousand times faster at best, dictionaries can probably do that.  The only time they're bad is when you need to iterate over everything in your game in a specific order.  You almost never need to iterate over everything in your game in a specific order.  Dictionaries and their little brother sets are one of the primary reasons I say that your hypothetical doesn't exist yet speed problem is probably algorithmic and switching languages is probably not necessary, at least when such threads come up.

My Blog
Twitter: @ajhicks1992

2015-03-02 09:14:53

Hi!

I didn't know BGT has dictionaries. Just curious, Genroa and Camlorn, what do you want to store in each dictionary value? Key = object refference, and value? Do you mean an unique id generated when creating a new instance of an enemy?

Thanks.

2015-03-02 10:21:16 (edited by Genroa 2015-03-02 10:22:02)

For my projects I used a generated ID solution. I generate a unique ID for each object or I use a "name" attribute. Then I store the reference as the value. (because unfortunately BGT dictionaries only accept strings as key sad )

The BGT help.chm contains all the informations you may need to know about BGT dictionaries smile

2015-03-02 16:24:29

Yeah.  To use an analogy, if it's a mud, the keys are the room vnums and the values are the room objects.  You can convert ints to strings, so problem solved.
I personally give everything in my games a globally unique id these days.  I'm not sure if BGT has a UUID generator, but if it doesn't you can just increment an integer somewhere.  You can then look these up by that id instead of referencing them.  Weak references (for those who know what they are) or any solution that relies on the GC to "do the right thing at the right time" is probably not what you want.  Gcs are very nice things to have, but you give up other guarantees about object lifetime; even when the object is removed from the array or whatever and nothing references it, there's no guarantee it'll actually be collected unless the BGT manual somewhere says that there is.

My Blog
Twitter: @ajhicks1992

2015-03-02 18:14:33

I have no idea how this works, but there is a way to run the GC explicitly (garbage_collect()).

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2015-03-02 18:51:21

I think garbage_collect() has to be called sometimes if you "send a lot of objects to destruction and create a lot of other objects". To clean the memory more often than BGT would smile

2015-03-02 19:08:25

I will still maintain until the end of time that you should never, ever rely on its behavior.

My Blog
Twitter: @ajhicks1992

2015-03-04 14:48:17

So, I've been looking into dictionaries, and they do seem like they are what I need.  I'm confused on a few points still, though.
First, how can I go through the entire dictionary to check for things? For example:
When I fire the weapon, a method on the weapon class is called, which goes through my array of wall objects, and stores any that intersect with the line segment created by my weapons fire. I then want to go through all the enemies, and store the points of any that intersect. I already have a function for this, it's going through all the enemies then performing the required actions on the right one that I'm having a bit of trouble with.
Thanks for all the great suggestions, though. This is my first real big project, and it's exciting when stuff finally starts to happen. smile

Prier practice and preparation prevents piss poor performance!

2015-03-04 14:51:40

You're better off arranging the keys in your dictionary so you don't have to iterate through all of them, but if you really need to, use the get_keys method.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2015-03-04 15:34:54

How exactly would that work? I need to check all the enemies on the level to see if they intersect with the weapon. Get keys seems like it will do what I need, though. Thanks.

Prier practice and preparation prevents piss poor performance!

2015-03-04 19:02:30

I am currently trying something : if an enemy is on the case x=3 y=2, I store its reference in a dictionary with the key "3;2". If something is in front of your weapon, you can instantly know it. And you remove the reference and store it with an other key when the enemy moves smile

2015-03-04 20:01:24

You're reinventing spatial hashes.  This is part of why I try to convince people not to use BGT in the long run, though unfortunately there's nothing that's quite so easy on day one.

My Blog
Twitter: @ajhicks1992

2015-03-04 20:48:59

Exactly camlorn. But I started my engine project in BGT... But I'm sure that one day I will port my project on another language. Everything is to create in BGT.

2015-03-04 20:51:12

yes. I'm coming to that realization far too late, unfortunately. If this weren't a school project I'd probably just recode in c++, or some other programming language. It feels like I'm at that point though where it's easier to just deal with it, and I've learned my lesson now, so I'll remember to not do that next time.

Prier practice and preparation prevents piss poor performance!