AI
BlitzMax Forums/BlitzMax Programming/AI
| ||
I had a topic deleted "best way?" dunno why, didn't get to see if any responses. I was wondering how to handle the AI ships in the enemyship list to shoot at the player, using the EBullet Type or Emissile Type |
| ||
oh man, I had posted like 5 replies to that. ::Grumble:: my best advice, start using STRICT immediately. |
| ||
http://www.blitzbasic.com/Community/posts.php?topic=65100#726843 |
| ||
do you have some code? |
| ||
http://www.blitzbasic.com/Community/posts.php?topic=55711 check out the PursuitTest program. |
| ||
i posted it in the other thread GAWD. |
| ||
ok basically what is happening is, I have several enemy ship objects. I want them each to fire a missile at the player, (obviously based on certain conditions) problem I am having is, only ship at a time is able to fire, and it is the last ship I instance. You press a button to add in enemies. So as you press, the new enemy picks up the firing. And you see the missile coming from that ship instead. Interestingly as well, the amount of damage being done by this "single" missile hitting your ship, is equivelant to the amount of enemy ships you have. FOR example, if a missile does 10 damage from one hit, if you have 5 enemeies instances, the missile that is fired does 50 damage. enemy missile Type: Type Etmissile Extends tmissile Field lastfired% Global list:TList = CreateList() Function FireTorp() 'creates the missile object and fires it really. Firemissile (ship.x , ship.y) End Function Function Update() 'Local eachenemy:tenemyship For emissile:etmissile = EachIn List emissile.age :+ 1 emissile.frame:+ 1 If emissile.frame = 30 Then emissile.frame = 0 emissile.x :+ Sin(emissile.angle) * (emissile.Speed)' + eachEnemy.current_speed *delta emissile.y :- Cos(emissile.angle) * (emissile.Speed)' + eachEnemy.current_speed *delta 'remove missile if is older than 150 If emissile.age > 150 PlaySound(missileExplosionFx:TSound) RemoveLink emissile.link End If Next End Function Function draw() For Local all:etmissile = EachIn list SetScale 1 + newscale, 1.0 + newscale'scales the missilees according to zoom SetBlend ALPHABLEND SetColor(255,255,255) MidHandleImage (all.photonImage) DrawImage(all.PhotonImage,all.x,all.y,all.frame) Next End Function '======================================================================================= 'create a new object missile based on the type weapon, adds each to a list, and appends 'deletes from the list as each missilees lifetime goes to 0 or as you fire. '======================================================================================= Function Firemissile(x#,y#) 'controls how rapid you can fire missilees. 100= 100 split seconds If (MilliSecs() - emissile.lastFired) < 600 Then Return Local emissile:etmissile = New eTmissile PlaySound(sound.CurrentmissileSound) emissile.frame = 0 For Local eachenemy:tenemyship = EachIn tenemyship.eshiplist emissile.angle = ATan2( eachEnemy.x - ship.x , ship.y - eachEnemy.y )+180 emissile.lastFired = MilliSecs() emissile.x = eachEnemy.x + (Sin(emissile.angle)) * delta'so torp orgin from ship emissile.y = eachEnemy.y + (Cos(emissile.angle)) * delta Next emissile.age = 0 emissile.link = ListAddLast(list,emissile) End Function End Type This is called in an AI() function in the main loop 'fires enemy missiles Function Fire() Local weaponRange = 600 'fire if distance is less than weapon range For Local eachenemy:tenemyship = EachIn tenemyship.eshiplist If ListIsEmpty(tenemyship.eshiplist) = False If ListIsEmpty(ship.shiplist) = False If ship.iscloaked = False If EachEnemy.iscloaked = False If eachenemy.distance < weaponRange etMissile.fireTorp() End If End If End If End If End If Next End Function in the main loop "AI()" is before these: etMissile.update() etMissile.draw() of course I want each enemy ship to fire on the player. so hence the for each loop in the fire() function there there is a for each loop in the FireMissile() function of the enemy missile type because, the missile must originate from the position of the enemy ship that fired it, and the angle/direction of the missile etc, must be calculated based from the ship that fired it, hence for that piece of code. fire missile is basically a create() function |
| ||
Well, that's some different code than you posted last time, but I'll try to help. You're mistaken by referencing "Ship.X" and "Ship.Y" in your fire torpedo function. You are also mistaken by referencing "EachEnemy" in your fire missile function. Neither Ship nor EachEnemy exist within the scope that you are referencing them. Actually, I'm assuming ship is a global value that represents your players object. But why then does your fire torpedo function always use Ship.X and Ship.Y? Shouldn't it take the X and Y of the firing ship as parameters? etMissile.fireTorp() Why are you calling fireTorp, a function, as a method? What you need to do is to give the enemy type an Update method. There's no reason that code that only acts on a single type should be a function. No, whenever you have code that only modifies a single type, it should probably be a method of that type. So then, each frame you do this local EachEnemy:TEnemy = Eachin EnemyShipList EachEnemy.Update() The actual code of update should handle repositioning and drawing the ship, and then evaluating the test conditions to see if the ship should fire a missile. Also, make sure give the enemy type a "LastFired" field. There is no reason that field should belong to the missile. Instead, each enemy should track when it was last fired. The way you have it now, the missile type itself is storing the last time it was shot (presumably in a global variable given the problems you are having) and hence, whenever ANYONE shoots it prevents everyone else from firing until that time has passed. Lastly, make the FireMissile() a method of the TEnemy type. So now you've got an Update() method inside of the TEnemy, and if the test conditions pass inside of Update() it calls FireMissile(), also a method inside of TEnemy. FireMissile needs to reference the X and Y field of the object calling it, which is trivial once you've made it a method of that type. Lastly, you can get rid of this line in your last block of code If ListIsEmpty(tenemyship.eshiplist) = False If eshiplist is empty, the "For Eachin" loop simply won't execute. Hence, you are wasting cycles testing for a condition that will never be true at the time of testing. Lastly, and this is the most important thing you can do to help improve your coding and catch random bugs is to use STRICT. In fact, I'm not trying to be rude, but I'm not going to offer anymore help until you start using it. Not using strict makes it exponentially harder to debug, especially when you only provide snippets of code. It's not worth my (or others) effort to try and help with your code when you aren't using strict as it's simply too hard to tell what might be the problem (for instance, you can reference variables that should be out of scope, but how can we tell?) |
| ||
the X and Y values of fire torpedo, are where to aim them at, hence ship.x, ship.y i am using strict dude why are you calling firetorp as a method because that's calling the function of the type, that way accesses a types functions without having to use a specific object of the type. |
| ||
You seem to be accessing emissile both globally and locally within the firemissile function. That can't be right... can it? I also think that the firetorp function doesn't seem to do anything than simply call firemissile. What does it add? I'm not saying either of these will solve your problem but it's poor coding and that can lead to 'odd' problems like the ones you are having. |
| ||
right, well I created the firetorp function as a test actually. dont remember but it was a test to see if a theory i had worked. also the emissile globally and locally. there is in fact a globaled emissile, declared in globals, and as you can see the firemissile function has a local emissile:tmissile in it...so yes it is possible that is causing an error. I have been trying to change it but the problem I am running into is that how would I set the fields of each missile object that need to be set in that firemissile function? because the enemy ships are at different positions each missile that gets fired needs to calculate the direction to fire the missile at, based off of where the enenmy ship that is firing at you is located. That's why I placed a for eachin loop there... it actually isn't correct as it is, its saying that for each ship in the enym ship list, and then goes on to only calculate for a single missile object. because you should use the local variable you declared in the for each in loop. my main problem is that I am basing the logic of this emissile type off of the missile type the player uses to fire missiles, which works flawlessly. and since there is only one player, i wouldnt run into the problems I am running into here because i dont have to factor in firing from multiple instances of my player ship as I would with the enemy fleet of ships. WHich leads me to the only conclusion, a re write of the code to handle the enemy missiles, forgetting the previous type, and taking into account from the beginning the fact that I have multiple instances to be concerned with regards to firing. Is it neccessary though that I need a separate missile type for the enemy? The reason I made it separate and to extend the type used for the player's missiles is because I ran into trouble properly updating enemy missiles with the functions in the other type, hence a new type and ovverriding functions. the missiles I might add work well with only one enemy ship instanced. |
| ||
because the enemy ships are at different positions each missile that gets fired needs to calculate the direction to fire the missile at, based off of where the enenmy ship that is firing at you is located Not a problem because you (or at least your list of tenemy) knows the position of each tenemy and you know the position of the player ship.When it's time for a tenemy to fire simply has a fire function/method within your tenemy type passing the tenemy x/y and the global playership x/y and use that information to call a tmissile.create(x,y,playerx,playery) function. Once the tenemy has fired it's missile it can forget about it or, if you need to know which tenemy fired add it to a list of tmissiles specifically for that tenemy. Once you have a list of tmissiles that are active the tmissile.update and tmissile.draw function can handle their movement. This code doesn't have the ability to target anything but you can add the code for that... It's quick and dirty... as always. |
| ||
yeah? well your quick dirty one helped last time, remember the explosions? :) thanks Ill have a look when I leave work. |
| ||
having a more concentrated look at home with my code. the problem with the firemissile function is that it cannot see the values of the x and y of the ship that is firing it because there is no ship visible to that function. if i do a local enemyship:tenemyship = new tenemyship sure it can see an enemy ship, but it will be seeing an entirely new enemy ship and not even the one or ones firing the missiles. |
| ||
Why is Fire a function? it should really be a method of tenemyship, Perhaps with a target parameter as well. |
| ||
you mean fireMissile() should be in tenemyship guess like i said couple posts above, have to rewrite keeping in mind its the tenemyship AI thats firing, which is going to be different from anything to do with one player controlled object. |
| ||
ok redI I was trying that before, didn't work out, tried it again and saw logically why it didnt work when I tried it before. minor adjustment and voila. will post exactly what solved it later. thanks for all the help guys. |
| ||
the problem with the firemissile function is that it cannot see the values of the x and y of the ship that is firing it because there is no ship visible to that function. Which is why, in your case, I suggested having your playership global. |
| ||
and so it could have stayed there. then there is the x and y of each enemy ship that the missile must originate from. |
| ||
and so it could have stayed there. Not sure what you mean by that. What could have stayed where? then there is the x and y of each enemy ship that the missile must originate from. which you take from your Tmissile x/y fields. |
| ||
Make FireMissile() a method of TEnemyShip. Call it with the parameters of the target locations X,Y. Then, inside of the FireMissile function, you can instantiate a TMissile with the target X,Y and the X,Y fields of the EnemyShip that is creating it. i.e. Type TEnemyShip field x:int field y:int field lastfired:int method FireMissile( targetx:int, targety:int ) if( millisecs() < lastfired + fireinterval) return 'enough time hasn't elapsed yet else local newMissile:TMissile = new TMissile newMissile.TargetX = targetx newMissile.TargetY = targety newMissile.x = x 'this assigns the missile the x position of the parent ship newMissile.y = y 'this assigns the missile the y position of the parent ship GlobalMissileList.Addlast(newMissile) lastfired = millisecs() endif EndMethod EndType |