Collision Sensor - Python issue

(Blender 2.62)

I’m working with Object Oriented Programming, where the main script is run from one central script controller, rather than attaching scripts to individual objects.

I have a Collision sensor attached to an And controller (to detect the pulse) on my Player object, which is meant to collide with certain objects around the scene.

My Python script accesses this Collision sensor and checks if it’s positive (if collision.positive:). I then have the script print the collision.hitObject, but this only prints a None value. Printing collision.hitObjectList also just prints an empty list “[]”.

I’ve tried to replicate this in a fresh blend file, but it would actually successfully print the Object in the console and I wasn’t able to get the same result as before.

Here’s what’s going on in a nutshell (rather, in a video):

https://youtu.be/BETX0YQxIRE

I can’t isolate the problem in the .blend file, so if I were to link it here I wouldn’t be able to take any content out to make the file lighter - with the exception of the textures. Please let me know if that would be necessary though.

I’m not exactly sure, but I think you can only access sensors/actuators of the currently active controller.

So, if you try to access the properties of a sensor on some other object, you would get something undefined.

This is something you could test.

I believe in the case of a single script used by multiple objects, you would need to be sure that you separate the variable assignments so parts of the script only run when it’s a certain object using it, so you would have to check for the different objects using the script before assigning values to the controllers and actuators for example.

I was able to isolate the problem.

First method:
The CORE scene contains the object that runs the script. It overlays the GAME scene where the player object exists.
The Collision hitObject prints as None.

Second method:
The CORE scene contains the object that runs the script, as well as the player object.
The Collision hitObject prints the proper object name.

I’m not sure what the exact cause for this is, but it would seem that the problem is due to the scene overlay. The script is obviously able to detect that the Collision sensor is positive, but, perhaps due to the difference in Scenes, it cannot properly identify the KX_GameObject.

The second method isn’t a feasible option for the Maze Creator game that I’m working on, featured in the video. Perhaps a method using Messages could work, but it isn’t quite as connected to the game system as I would like it to be.

Here’s the .blend:
collision_isolated.blend (95.9 KB)

CORE scene uses method 1, and CORE2 scene uses method 2.
Edit: Left click to add the Player object

I’m not sure, but I think the blend doesn’t work the way you describe out of the box. For one thing, you have to activate the player object’s layer in the Game scene, right? Secondly, nothing happens in any of the scenes (no visual or console output). I’m guessing you had a logic brick that showed that the sensor activated. Are you sure this is the way that the blend should function? I don’t want to try to ‘fix’ it myself and end up destroying the purpose of this object-oriented approach that you have, which is a little confusing, but also interesting. What made you try this approach as opposed to the normal approach?

It’s working fine for me. I downloaded the .blend again to verify this. It starts in the CORE scene, which should overlay the GAME scene once the game starts. The CORE2 scene operates on its own without overlaying any other scenes.

Edit: Darn, completely forgot about this part: Left click adds the player.

Also, I wanted to try the Object Oriented approach because, to me, it seemed more organized and connected, and made certain properties and functions easier to access. It also seems to add a bit more control to the order of functions, rather than the typical BGE scripting approach.

You can still follow the OOP approach, and execute the code on the relevant objects.

Check out my RTS Controls tutorial, where I subclass from KX_GameObject.

I tried to subclass from the KX_GameObject from the experimental .blend I posted above, but it doesn’t seem to be working. I used the print(dir(object)) functions to print the contents of the object afterwards, but the main() function that I defined didn’t show up. I’m not sure what I’m doing wrong here:

subclass_problem.blend (95.1 KB)

The OOP approach IS to apply the logic at the objects :slight_smile: that’s why it is called object orientated and not procedural.

Forget the name main. This name has no meaning and does not describe a tiny bit of what the method does.

Better start class names with Upper letters (see PEP#008) Otherwise it is hard to distinguish variable names from class names.

Creating a subclass of KX_GameObject alone just defines the class. It does not create this class.
What you are looking for is a sort of prototyping and reference replacement.

You want to replace the existing reference of a KX_GameObject instance with your own implementation that is a (data) copy of the original instance.
After that all references to the old instance should be replaced by references to the new instance.

The BGE is doing that for when you initialize a KX_GameObject. The BGE requires the reference to the original instance on initialization.


import bge
class MyGameObject(bge.types.KX_GameObject):
  def __init__(self, originalGameObject):
      # The BGE performed the prototyping and the reference replacement
      print ("created a new instance {0} from the KX_GameObject {1} with name '{2}'".format(
                id(self),id(originalGameObject), self.name))

  def printNonsense(self):
      print("Nonesense at",id(self))

This is just the definition. This alone does nothing.

you need to instantiate your class to perform the prototyping and replacement:


def injectMyGameObject(controller):
  gameObject = controller.owner
  if not isinstance(gameObject, MyGameObject):
      newGameObject = MyGameObject(gameObject)
      gameObject = newGameObject
  gameObject.printNonsense()

Example: place the above code in a file demo.py and execute Python Module: demo.injectMyGameObject

Be aware to create only one instance as shows.
Be aware to create the instance before you access the customized attributes.

Thanks, Monster. I was able to create a subclass and apply it to my object. I made a function to run from the new KX_GameObject that detects the collision sensor and gets the hitObject from it when it’s positive. I can run gameObject.getCollision() now from my main script.

The original problem still remains though: The script running in another scene isn’t detecting the collision.hitObject, while the script running in the same scene as the objects is able to identify the hitObject with the same code setup. Maybe I’m missing something with what Goran meant, or maybe this is just an issue with how the BGE handles things.

collision_hitObject_problem1.blend (74.3 KB)

You can store the collision results in the “sensor” object.
Then can directly transfer the data if the “sensor” object knows the other object(s)
or
the other object(s) can grab it when it gets notified by the “sensor” object (e.g. via message)

It seems necessary then that I should run another script in the GAME scene. This is the alternative method I’m using:

playerCollision.py on the player object


    collision = cont.sensors['collision']
    
    core = objects('CORE')['CORE_Camera']
    col = core['core'].game.player.collision
    
    if collision.positive:
        col.positive = True
        col.hitObject = collision.hitObject
        col.hitObjectList = collision.hitObjectList
    else:
        col.positive = False
        col.hitObject = None
        col.hitObjectList = []

This script accesses my Core system and assigns the results from the Collision sensors to the necessary variables. I had thought of doing this before, but I was hoping that there was a way to accomplish this without having to run another independent instance of a script.
Gets the job done :slight_smile:

Thanks

Finally you can connect all sensors with controllers of your central object.