Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

Dark GDK / Please Help Me With AI

Author
Message
NoviceNate333
7
Years of Service
User Offline
Joined: 7th Dec 2012
Location: United States
Posted: 19th Jun 2014 11:20
Hello, everyone,
I am Stuck.I have been trying to create the AI class for the game I am working on and there are two major problems I am having with the code.
1: When the enemies Death state is 1 the enemy just stands static and refuses to play the dying animation.
2: i can not properly instantiate multiple enemies with out them sharing the same health. I attempted to, but for some reason my methods are not working. can some one please help me... here is my code.

Attachments

Login to view attachments
mr_d
DBPro Tool Maker
12
Years of Service
User Offline
Joined: 26th Mar 2007
Location: Somewhere In Australia
Posted: 19th Jun 2014 14:02
hi NoviceNate333,

although this doesn't help specifically in answering your question; it looks like you are trying to use a multi-dimensional array to hole your enemy states and health:

int enemyHolder[maxEnemy][3]

this isn't the best option to do this type of thing; consider using an array of structs instead.

from what you have it looks like enemyHolder[maxEnemy][2] is holding the state of the enemy and enemyHolder[maxEnemy][3] is holding the health of the enemy, what are enemyHolder[maxEnemy][1] and enemyHolder[maxEnemy][0] used for?

NoviceNate333
7
Years of Service
User Offline
Joined: 7th Dec 2012
Location: United States
Posted: 19th Jun 2014 18:23
Well, I planned on using the 0th index of the array as types of enemies for example 1 be a zombie and 2 be dragon. the 1st index I planned on using for way point object ids.

please elaborate on structs. I am afraid I am not familiar with them.

Thank you for your fast response.
The Tall Man
6
Years of Service
User Offline
Joined: 16th Nov 2013
Location: Earth
Posted: 19th Jun 2014 20:41 Edited at: 19th Jun 2014 22:04
I agree that structs would be preferable to multi-dimensional arrays here.

A struct is basically the same thing as a class. It can hold data members and functions. Although more typically, structs are used just for data members. And they all tend to be public.

But rather than using structs, you may want to consider taking it a step further and creating an enemy class instead... Depends on how you wish to organize it. That would also eliminate your need for globals, and it would make your code simpler, more modular. Each enemy would be a new enemyClass instance.

But a struct would be something like this:



You can, of course, make all your struct members ints if you want. I just used different types there to illustrate that it could be done.

Also, Microsoft memory-aligns types in a struct. So the way I've defined it, that unsigned char would use 1 byte, then have 3 bytes wasted space, so that the following int could be 32-bit aligned. You may want to keep that in mind as you use structs (and classes). But it probably won't waste enough memory to matter for your project. So if it's confusing at this point, then don't worry about it.

Judging what we see is the greatest blinder and self-limiter in the universe.

What we perceive is never reality. It is only a story we tell ourselves based on our current perspective, which has far more to do with our beliefs about ourselves than with anything else.
The Tall Man
6
Years of Service
User Offline
Joined: 16th Nov 2013
Location: Earth
Posted: 19th Jun 2014 20:55 Edited at: 19th Jun 2014 20:56
As for why your enemies are sharing states... I've noticed you're using the object number in place of what you said you were using for Type. From a glance, it looks like you might be using that first index for multiple (conflicting) uses.

First of all, db object numbers begin with 1, which would allow you one less than your maxEnemies, as you've defined it. If you want to index your enemy by object number, then define the maxEnemies by maxObjects you'll have. If your CreateEnemy() function is called with an objectNumber > 2, it'll overflow your array.

Also, you start X at 202 and continue until it's less than numberOfEnemies (<= 3), which effectively disables those loops.

Judging what we see is the greatest blinder and self-limiter in the universe.

What we perceive is never reality. It is only a story we tell ourselves based on our current perspective, which has far more to do with our beliefs about ourselves than with anything else.
NoviceNate333
7
Years of Service
User Offline
Joined: 7th Dec 2012
Location: United States
Posted: 20th Jun 2014 01:27
I will experiment making the enemey class without the 2d array but when I attempted this earlier I couldn't create an enemy without having to load the model multiple times and since my enemy has animation dbInstanceObject is a no go because it only supports static objects. Is there a way around this?
The Tall Man
6
Years of Service
User Offline
Joined: 16th Nov 2013
Location: Earth
Posted: 20th Jun 2014 03:12 Edited at: 20th Jun 2014 03:18
There's no reason why you'd have to load a model multiple times. When you create a new enemy, that "enemy" is a new instance of your enemy class. Being object-oriented, the enemy class contains data about the enemy, including object number, animation ranges, and so on. Then what the "enemy" does are what the functions are for. To create multiple enemies from a single prototype, you can have an enemy prototype class as well, which each enemy stores (or creates) a reference to.

For example:



Judging what we see is the greatest blinder and self-limiter in the universe.

What we perceive is never reality. It is only a story we tell ourselves based on our current perspective, which has far more to do with our beliefs about ourselves than with anything else.
NoviceNate333
7
Years of Service
User Offline
Joined: 7th Dec 2012
Location: United States
Posted: 20th Jun 2014 07:32
I saw that you used dbCloneObject for some reason if I use the clone method I get a linking error and I know dbInstanceObjec t only works for static objects like tees and rocks and to my knowledge do not support animation.
The Tall Man
6
Years of Service
User Offline
Joined: 16th Nov 2013
Location: Earth
Posted: 20th Jun 2014 11:02 Edited at: 20th Jun 2014 11:06
Yeah the reason I used dbCloneObject is because you said the dbInstanceObject didn't work for animated objects. Besides it's been my experience that dbInstanceObject is buggy anyway.

I never had a linking error with dbCloneObject before. But I found a thread about it, and tried the 3 parameter version - and got the linking error. I've always just used the 2 parameter version. Anyway, the solution to get it to link is here. Turns out there's a mismatch in the header declaration and its definition the library. Easily correctable.

http://forum.thegamecreators.com/?m=forum_view&t=145678&b=22&msg=1695886#m1695886

Judging what we see is the greatest blinder and self-limiter in the universe.

What we perceive is never reality. It is only a story we tell ourselves based on our current perspective, which has far more to do with our beliefs about ourselves than with anything else.
NoviceNate333
7
Years of Service
User Offline
Joined: 7th Dec 2012
Location: United States
Posted: 21st Jun 2014 01:57
Ok so i used dbClone(int,int) effectively with out the share data flag set to 1 and it worked perfectly. also i watched a couple of videos on structures and read some stuff on cplusplus.com and i have successful implemented it into the ai code. I also made it a class so that it is more modular because I plan on using this code again in the future.
I still have one problem when i set the alive value to false and use an enum to use cases as animations the death animation still does not play. He just freezes in the original static pose.




The Tall Man
6
Years of Service
User Offline
Joined: 16th Nov 2013
Location: Earth
Posted: 21st Jun 2014 03:08 Edited at: 21st Jun 2014 03:16
Awesome!!

On your issue... well to be dead is to not be animated, by definition. Perhaps you mean to play (once) the dying animation before clearing the Alive flag? You need to let the animation finish playing first.

On a slightly separate (but not completely) note, referring back to my enemyPrototypeClass idea above... You could have an animation struct, like this:



Then in your EnemyPrototypeClass, add:



And to your EnemyClass, add:



Then you can replace your switch statement above with this:



Judging what we see is the greatest blinder and self-limiter in the universe.

What we perceive is never reality. It is only a story we tell ourselves based on our current perspective, which has far more to do with our beliefs about ourselves than with anything else.
The Tall Man
6
Years of Service
User Offline
Joined: 16th Nov 2013
Location: Earth
Posted: 21st Jun 2014 06:59
btw, if you had a Character class instead of an Enemy class, then you could include a CharacterType, such as:

Enemy
Friendly
Bystander
Victim
Villager
Worker

Then a subtype, which for enemy would be things like zombie, soldier, madman, doctor, agent, etc.

Judging what we see is the greatest blinder and self-limiter in the universe.

What we perceive is never reality. It is only a story we tell ourselves based on our current perspective, which has far more to do with our beliefs about ourselves than with anything else.
NoviceNate333
7
Years of Service
User Offline
Joined: 7th Dec 2012
Location: United States
Posted: 25th Jun 2014 05:04
Thank you "The Tall Man" for all of your advice. sorry i have not replied in a while. I plan on making the character class you refereed to and thought that will probably be the best idea considering my primary focus is using oop so i can reuse my code in a later project. I will post the final result.
The Tall Man
6
Years of Service
User Offline
Joined: 16th Nov 2013
Location: Earth
Posted: 25th Jun 2014 07:24
Cool! Yeah, OOP is nice. And I like to create reusable code, too. It makes everything so much simpler. You seem to be quite resourceful and picking this up fast. Best of luck - and enjoy!!

Judging what we see is the greatest blinder and self-limiter in the universe.

What we perceive is never reality. It is only a story we tell ourselves based on our current perspective, which has far more to do with our beliefs about ourselves than with anything else.
NoviceNate333
7
Years of Service
User Offline
Joined: 7th Dec 2012
Location: United States
Posted: 12th Jul 2014 11:15
Ok so i have fixed a lot of my issues , and organized a lot of my code. That being said I hope you are still checking this post i am sorry for the late response, for i have just moved and my network was just not turned back on. I am now Stuck with the following problem. When one enemy dies the other enemy cannot be killed.It is as if some how their health is still being shared even though I am using structs to hold members such as int health, int objectID, and bool alive.
Just in case I am going to make a second post on the forum to get more attention from other people as well.
Here is my character class which is the base class for my enemy class.


Here is the Enemy class that contains the basic logic for AI until i get the health and dying part to function correctly



Please anyone, if you have the knowledge to help me do not hesitate I have been stuck on this same problem for a long time now with a lot of help from "The Tall Man" and some advice from "mr_d" thanks in advance
mr_d
DBPro Tool Maker
12
Years of Service
User Offline
Joined: 26th Mar 2007
Location: Somewhere In Australia
Posted: 13th Jul 2014 07:13 Edited at: 13th Jul 2014 07:25
Hi NoviceNate333, good to see that you've taken on the advice you were give by The Tall Man, and incorporated it into your code...

Again, I don't know if this will help you with your specific problem, but I think you need to provide more of your main code logic before we can determine why you are running into this problem.
From what I can see from the code you provided, your character class has an alive status and a health value, and it looks like you decrease the health value based on a random hit damage.
this is fine as far as it goes, but it doesn't look like you ever check your health value and change your character's live status based on it's health (or lack thereof).
you also seem to set the action to DIE if the distance is less than a certain amount when it takes a hit; and you call the die method of the class, but this seems to only play an animation (I'm not familiar with the DarkSDK library, so am only guessing on what those functions do).

EDIT: reading again what your actual issue is and the bit where you say you haven't completed the health or dying parts yet, it looks that the problem for now is that when you kill an enemy, their id is not removed properly from the whole set of enemies and that the other enemies that won't die are possibly using the same id as the one that was supposedly killed already.

It would be good if you could include a functional mini example of your problem so that others can run and see the problem themselves.

I suggest you include a series of debugging print statements to the screen (usually located at one of the corners) so that you can keep track of the values of each of the main things you are working on, like enemy id, heath and status, etc. this make it much easier to see when values do not match expectations after certain events have occurred.

The Tall Man
6
Years of Service
User Offline
Joined: 16th Nov 2013
Location: Earth
Posted: 13th Jul 2014 20:19 Edited at: 13th Jul 2014 21:12
You may want to consider making each character a class instance, instead of having one instance handle all your characters. That's what I meant before. But I've created many classes that handle everything in one instance as you have. There are advantages to doing it each way. One advantage to designing your class to handle one character (instead of all of them) is simplicity. Since you've said your goal is to learn OOP, I would recommend taking that route, as that is more OOP-oriented.

I've noticed that your takeDamage() function can result in your health becoming negative. So when checking for death, you may want to check if that health is <= 0 rather than != 0. But I didn't see any such check in your code.

I also notice you're implementing your function definitions in the same place you're declaring them. For more OOPness, greater simplicity and modularity, I would recommend, doing your declarations (prototypes) in an .h file and your definitions (implementation) in a .cpp file. For example:

character.h


character.cpp


One of the benefits of doing it this way is you can glance at your .h file for a quick-reference of available functions. And the definitions and declarations really should be separate, as you don't want to confuse the calling of the functions with their implementations, when calling class functions from an outer scope. I believe the term that refers to this principle is encapsulation. It's more modular, far cleaner, and it compiles faster. Microsoft managed code tends to violate this principle (and many others). Their code and style are horrific examples, abominations, absolutely not to be followed. Notice what I moved over to Private in character.h. Any functions that will only be called from within the class and not from outside of it should be moved to Private as well. Also, it's good to keep your naming conventions consistent. Sometimes your function names start with capital letters. Other times they start with lower-case letters.

One other observation - you used constants throughout your code. Generally it's a good idea to define those constants all in one place (for example using #define), then it's easier to remember what you were thinking when you decided on their values, and to change them later if needed. For example, instead of:



Have something like this:




Lastly, I second what mr_d said about debugging your program as you go. That's a real key and can reveal much. But with Visual Studio, you don't need to add print statements as you might in BASIC. Just compile for Debug (which is the default) and set breakpoints, and inspect variables when the breakpoints are triggered. For a group of variables you intent to regular inspect, you can add them to a watch list (Add Watch), which will display them all in one window.

Judging what we see is the greatest blinder and self-limiter in the universe.

What we perceive is never reality. It is only a story we tell ourselves based on our current perspective, which has far more to do with our beliefs about ourselves than with anything else.

Login to post a reply

Server time is: 2019-12-15 08:00:45
Your offset time is: 2019-12-15 08:00:45