Problem with Spawns AND how can i change blender logic properties into pythoncode?

Hello,
i will talk about my Blendfile and the Problems i got first, before i ask my questions. Please be gentle, i am quite inexperienced with the BGE and with Python. If you want to know the Questions first, scroll down please.
I will add Blendfiles if needed.

Short Description:
I have a Testgame, two Spaceships, one controlled by the player, one is using a ray for shooting calculation and has a steering Actuator to chase the player if it comes near. I will call them enemy_ship and player_ship.

Properties in both objects:
HP - Hitpoints of the object
mass - tells Laser that they should end their life when colliding.
player/enemy - to distinguish roles. the Near Sensor of the enemy reacts on the Property player

Property in the enemy object only:
near - tells if the player is out of range (0) for following and shooting, near enough for slow follow and shooting (1) or very close for collision-melee-attack (2).

Testsetup:
Aims:

  • a) The Properties mentioned should be displayed, i toggled the option in blender.
  • b) The HP should be subtracted on collision with Laser-hits and player_ship & enemy_ship direct collision.
  • c) The Objects should end after the HP are at 0.
  • d) The Enemy Ship should chase after the player.

Scenarios:
1)
The Player_ship and Enemy_ship are at Layer 1.
What happens:
a) fine - everything is displayed right
b) good - HP are subtracted on both ships
c) yes - ships can both die
d) nice - the chase works!

The Player starts at Layer 1, the enemy_ship is spawned via empty (it is located on a different layer).
a) The Player “HP” are displayed right, “near” and enemy “HP” are not displayed right -> stay at 100 and 0.
b) Both ships can die. The Calculation works.
c) “”
d) The chase works.

The Player starts at Layer 2 and is spawned by an Empty, the Enemy is at Layer 1 from start without spawn.
a) Near and HP of Enemy are displayed right, (after endobj the value stays where it was). Player HP are displayed false.
b) Both ships can die, the Calculation seems right.
c) “”
d) The steering isnt working. The Enemy charges onto the Player, but it gets stuck and cant change direction.

  1. Both Ships are at a different Layer and spawn via Empty.
    a)No Property is displayed correct!
    b) Both Ships can die
    c) “”
    d) The Steering isnt working.

My conclusion…:
…was, that the Properties get an issue, when the Object spawns from a different Layer. I tried it with Delay and without. No change.
Or is it maybe an other Issue with the Steering Actuator?
I am not sure, because the HP are calculated correctly in all cases. I found someone who wrote “desgraph problem” and update does not function well. Sorry, i do not understand “very well” what that means or how i can solve that.

Thats confusing me too. Before testing it a second time, sometimes Player or Enemy were invincible (b was not fulfilled). Maybe i solved it ?

And another Issue i like to mention, in the progress of work blender used to crash every time, when the Enemy was “ended” and the Properties were displayed. Now, Blender does not care anymore.

My Questions and Requests:

  1. Please tell me about Bugs, it may help me :slight_smile:
  2. I thought about solving the Problem with Python at first. If it really is a problem of blender and updates of properties.
    But how can My Objects tell each other that they are “player” and “enemy”. I like to rebuild the functionality i used with logic bricks in python, but i dont know how. Messages seem like a good starting point, but i need to tell an object directly (but dont know whom i tell!) or i need to tell every Object via message, but how can the enemy find out that the Player is really near?
    If you can give me some hints to get out of confusion it would be nice :slight_smile:

Optional Bonus :
3) My Parented Camera on the Object does not work too when it is spawned, any idea to fix that?
4) Tell me whatever you think could help.

Thank you for your time and effort!
JMH

Yup, properties don’t display right if they are on different layers.

I would recomend doing it in python, as I find logic get’s confusing quickly for AI and such.
The prefered method for programming in the game engine is Object Oriented. What this means is that your player knows it is a player, but does not know about the enemy. Your enemy knows it is the enemy, and what to do when it see’s the player, but does not know anything about the player.

So you have to have a way to distinguish them. The most common way is to give the player a property ‘Player’ and the enemy the property ‘Enemy.’ Then you can create a list of all the enemies (and all the players!).
To create such I list I may do something like:


playerList = [o for o in bge.logic.getCurrentScene() if 'Player' in o]
player = playerList[0]

Then I can use the player ID for anything: track-to actuators, finding the player’s velocity, steering actuators etc.

I can also use it to get the distance between two objects.
Let’s say I have ‘own’ being the enemy object, and ‘player’ being the player object, then I can say:

distance = own.getDistanceTo(player)
if distance < 50:
    '''The player is close to me, attack!'''
else:
    '''keep looking'''

If you need more help, just ask.

Thank you for your answer sdfgeoff.
The logic behind your idea is fine, but i can’t put that piece in my image of the whole.
I looked in the www and found usefull stuff, about Listoperations:


or samples for functions: http://www.tutorialsforblender3d.com/GameModule/Modules248/ClassKX_GameObject.html
but, there is still one thing i do not understand. How is the communication of objects in Blender working?
I will ask my question and point out my problem then.

  1. Where do i “locate” that list? In the Player? Or a neutral point, like the worldobject or an special object only for python-operations?

If i have a script in my playerobject where the List is generated and modified, and an enemy is spawned, that player can not know about the enemy, when it spawns.
With a message from the spawned enemy, which can tell the playerobject the Reference of the Enemy, the player may get to know about the enemy and can change the List. I am not sure about the way the functions are implemented in Blender.

I am a little bit confused, maybe because i “was” used to (Basics of) Java where i had a main method, which was the basis for branches of modules. In Blender there is already a main method/program running, and different objects are instantiated, so where do i find the point to modify my main method for communication of the different objects? There have to be a portal where my objects can chit-chat, but i did not get it so far. Otherwise they talk in the void and nothing happens.
I hope i was clear enough, if not, i will try to understand and describe my Problem better!
I read monsters guides, but maybe i should read it again? Can you tell me what to read?
http://blenderartists.org/forum/showthread.php?240729

  1. I mentioned, that my camera (Layer 2) was parented on my player object (Layer 2). The parenting got lost, when the Object were spawned by the Spawnempty (Layer1). That was a property issue too? And could be solved with python? Maybe parenting the Camera with Python, after the Object was spawned? And if the object is killed, resetting the Position and unparenting the Camera, may help ?
    If you have better ideas, tell me :slight_smile:

Thank you for your patience!

Scripts run every frame. So every frame you have to generate the list. You can store it somewhere if you like, but when then when an enemy dies, you have to re-generate the list anyway, so why not do it every frame? Then it’s just kept as a local python run-time.
For lists that stay around longer (such as menu buttons, if you manage them with a list), then you can store it permanantly, otherwise there’s little point.

Why do objects have to communicate? The enemy does not have to tell the player where it is. The player can find it out. The playerObject/script.
So if I wanted to find another objects position, first I can get the object by name:

otherObj = [o for o in bge.logic.getCurrentScene().objects if o.name == 'otherObjectName'][0]

or by property, like I showed you in the post above.
Then with that object you can do things like:

enemyPos = otherObj.worldPosition
otherObj['health'] -= 10
etc

If you want things to be stored a little more permanantly between objects, you can have a look at the bge.logic.globalDict, which is a dictionary that can be easily accessed by all objects/code run from blender, and is preserved through frames and scene-changes (you can even save it to a file with logic bricks!)

Parenting is preserved through add-object, but you only have to add the parent.
If things can die, it’s better to re-spawn them every time rather than just reset their position. The reason for this is that it clears any left-over things that have happened to the previous player. Such as health. Instead of having to manually reset the health, when you spawn a new player, game logic properties are reset. The disadvantage is that you then have multiple objects with the same name.

I’m not quite sure I’m understanding you fully though, so if you want to make a diagram/flow-chart it’s often very useful.

thank you so far, i am close to my solution. But i now have a python problem.
Very helpful was this article, thanks again to the same person :slight_smile:
http://blenderartists.org/forum/archive/index.php/t-271910.html

I dont know how to do what i did in Java (ages ago).
What i get: Type-Error: ‘int’ objext is not subscriptable.
Ok, i used the countvariable i, sure it is an integer. But why am i not allowed to use it as key for my lists? Or the better asked question, how do i use right syntax to solve the problem?

I want to acess the list playerlist and check if the first object is more close (getdistance) to the enemy , the owner of the script, than the second player in the playerlist. And if there are more players, it should be checked for each entry of the list.
The idea was, use the expression len(playerlist) to check the listlength and after that compare the distance of the first player with the second, save only the reference to the most close player + the distance and go on.
len() works, but the part after this does not.




import bge

def main():

    cont = bge.logic.getCurrentController()
    own = cont.owner
    # keyboard optional-future use: cheatcodecombination, like: destroy all enemys
    keyboard = bge.logic.keyboard
    #scene
    scene = bge.logic.getCurrentScene()
    print(scene, "Scene-check ok, scene exists")
    #scenelist - just for testing the command.
    scenelist =  bge.logic.getSceneList()
    print(scenelist, "is the scenelist")
    #actuators - controll movement/behavior
    melee = cont.actuators['melee']
    if melee :
            print(melee, "actuator melee check alright, it exists")
    ranged = cont.actuators['ranged']
    if ranged :
            print(ranged, "actuator ranged check alright, it exists")
    #search for property 'player'
    playerlist = [s for s in scene.objects if 'player' in s]
    if playerlist :
            print(playerlist, "this is the list with the objects with property player")
    # get length of playerlist (how many players are in the list)
    pLl = len(playerlist)
    print(pLl, "playerobjects are in the scene, thats the length of the playerlist")
    #forloop , for chosing which opponent/player should be targeted
    #here begins the Problem. i have an Integer i, which i wanted to use to      
    #scroll in the List 'playerlist'. but i am not allowed to do that. How may i 
    #solve that problem?
    i = 0
    print(i , "is the value of i before the forloop" )
    for playerlist in range(0,pLl):
        print(i , "is the value of i in the forloop" )
        #Funktion Getdistance for every Objekt
        #+++++++++++++++++++++++++++++++++++++that is the problematic line. i 
        #have a list, which should be gone through, loop by loop / step by step/  increment by 
        #increment of i. Then i want to compare the distance of multiple 
        #playerobjects..with blenders gameengine functions.
        distance = own.getDistanceTo(playerlist[i])
        print(distance , "is the distance to the player", i)
        #i = i + 1
        # more code which makes the enemy find out which target is closer. After 
        #that an blender actuator will be activated, gets the reference to the 
        #player-object and the enemy will follow the player.


main() 



If you have an good idea how to solve the error, let me know :wink:

I thought about making a new thread, but anyway, the search function ist good :slight_smile:
renaming my thread would be nice, but it looks, like i cant do that.
I want to finish the code to something which is running, before marking the initial problem as solved. Maybe someone thinks as weird as i do, so i will go on (hoping that you help).

I reduced the Problem which i have now, it is the “int object is not subscriptable error”.
I do not get, how to increment through a list in a loop.
i tried just for fun, to use my increment variable i as string ( print(playerlist[‘i’],“is playerlistentry i”) , but the console tells me, that i should better use an integer. I did that again, but…i am not allowed to do that? it is confusing.


import bge


def main():

    cont = bge.logic.getCurrentController()
    own = cont.owner
    #scene
    scene = bge.logic.getCurrentScene()
    print(scene, "is the current scene") 
    #search for property 'player'
    playerlist = [s for s in scene.objects if 'player' in s]
    if playerlist :
            print(playerlist, "is the List with the property x")
    i = 0
    pLl = len(playerlist)
    print(pLl , "is the length of the playerlist")
    print(i , "is i")
    print(playerlist[0], "Playerlistentry 0")
    print(playerlist[1], "Playerlistentry 1")
    print(playerlist[i],"is playerlistentry i")
    
    #forloop
    
    for playerlist in range(0,pLl):
        print(i , "value of i in forloop-beginning" )
        #same as before but, next line provides "int object is not subscriptable ERROR!" why? and how is it to solve?
        print(playerlist[i],"is playerlistentry i")
        
       
main()


What is the console telling me:

Blender Game Engine Started
Scene is the current scene
[Suzanne, Spaceship Collision] is the List with the property x
2 is the lenght of the playerlist
0 is i
Suzanne Playerlistentry 0
Spaceship Collision Playerlistentry 1
Suzanne is playerlistentry i
0 value of i in forloop-beginning
Python script error - object ‘Enemy Collision’ controller ‘Python’:
Traceback <most recent call last>:
File “errorcheck_int_not_subscriptable1.py”, line 31, in <module>
File “errorcheck_int_not_subscriptable1.py”, line 28, in main
TypeError: ‘int’ object is not subscriptable
Blender Game Engine Finished

Well…i have no idea how i could solve that problem in my forloop. defining i only in the forloop did not help.
And here another Question: How can i copy the stuff i quoted from the console. I wrote it by hand, that is not very comfortable. Is there another solution?

Have a nice day!
Thanks for reading

solution of my error:

  for playerlist in range(0,pLl):

should be changed to

for i in range(o,pLl):

or

 for i, player in enumerate(playerlist):

And very helpful was sdfgeoff non only in his direct attempts, but his earlier works :slight_smile:
Thank you !

Script for targeting closest enemy:
http://www.pasteall.org/39810/python