Help with grab object script

This is a simple grab object script:

def grab(cont):    own = cont.owner
    grabcol = cont.sensors["grabcol"]
    if own["active"] == 1 and grabcol.positive:
        target = grabcol.hitObject
        target.applyForce((own.worldPosition - target.worldPosition) * 100000)
        target.setLinearVelocity([0, 0, 0])
    if not grabcol.positive:
        own["active"] = 0

It identifies if boolean active is true then applies a force between the collision box and hitObject. It then sets the linear velocity of the hitObject to 0, 0, 0.

I would like to make this more like the valve source engine method of grabbing objects (prop physics). This method “loses” the object when moving too fast and when the grabbed object collides with another object it goes flying at enormous speeds… Any fixes I can make?

Thanks :slight_smile:

You “lose” the object because your active grab depends on a collision sensor for the entire period (which can loose contact). To avoid this, you should use multiple functions that represent different states for grab (where you can set conditions that must be satisfied to pick something up), and for hold, which will depend on depressing the relevant mouse button.

See how I do it in my grab system tutorial:

I don’t know of a way to make it “Valve perfect”, because the BGE doesn’t really offer certain bullet features that would make that possible … Although, I would recommend looking at physics constraints, because that might provide some options (but I think they would have to be really ugly hacks).

Ahh… You, sir, are a genius! Great tutorial! :slight_smile:

Okay so I tried out a few things, and I REALLY don’t like using states for scripts (just a personal preference). Is there a way to do the following?:

import bgeimport GameLogic as g
cont = g.getCurrentController()
own = cont.owner

grabcol = cont.sensors["grabcol"]
hitobject = grabcol.hitObject

if own["active"] == 1:
    hitobject = grabcol.hitObject
    hitobject.applyForce((own.worldPosition - hitobject.worldPosition) * 10000)
    hitobject.setLinearVelocity([0, 0, 0])

Assign assign the collision object to a property/variable, but prevent it from setting its value back to “None” unless another object is collided with while active is false? (The collision hitObject variable needs to not be None while active == 1.

Are you talking about logic brick states?

I don’t like those either, but if you watch my video, you can see the mental model of a state machine encoded into functions.

There is only one function that runs at any given time, and which depends on what self.main was last set to - that determines what “state” you’re in, but it has nothing to do with states in the logic brick system.

def grab(self):
    if grab_condition:
        self.main = self.carry

def carry(self):
    if drop_condition: # typically, a mouse btn release
        self.main = self.grab

I understand how your “states” work by setting functions as other functions, thereby eliminating the other function until it is activated again.
I’m new to python and don’t really understand classes yet. They’re like a function collation containing functions or something (still learning how to use them).
So I tried to copy your method from your tutorial (practically word for word):

import bge
import GameLogic as g
cont = g.getCurrentController
coltarget = cont.sensors["grabcol"]
rclick = cont.sensors["rightclick"]

hitobj = None #self.pickup

main = pickup

def pickup():
    if coltarget.positive and rclick.positive:
        hitobj = coltarget.hitObject
        main = carry
def carry():
    delta = cont.owner.worldPosition - grabbed.worldPosition
    grabbed.applyForce(delta * 1000)
    if rclick.positive:
        main = pickup

def main(): #no clue what this should do...

How do I execute this properly? Do I need to use classes for this?

Also, how do I make it detect if the object is still alive? (If it dies, reset the states.)