views:

303

answers:

4

I have this script in a game that I am making. This will be used in the Blender game engine. Blender runs scripts over and over from top to bottom continuously, so if I declare a variable at the beginning of the script, it keeps being initialized over and over.

#The current location of the object
loc_x = obj.getPosition()[0]
loc_y = obj.getPosition()[1]

#The velocity of the object
velocity_x = 0.09
velocity_y = 0.03


#If the location of the object is over 5, bounce off.
if loc_x > 5:
    velocity_x = (velocity_x * -1)

if loc_y > 5:
    velocity_y = (velocity_y * -1)

#Every frame set the object's position to the old position plus the velocity
obj.setPosition([(loc_x + velocity_x),(loc_y + velocity_y),0])

Basically, my problem is that in the if loops, I change the variable from its original value to the inverse of its old value. But because I declare the variable's value at the beginning of the script, the velocity variables don't stay on what I change it to.

I need a way to change the variable's value permanently or declare it only once.

Thank you!

+2  A: 

Put the velocity_x and velocity_y declarations before the loop. If you're using classes, make them attributes of the object and intialize them just once, inside its __init__().

EDIT: I don't know how the Blender game engine works, but in addition to having the script in a big loop, there should be a way to intialize stuff before the loop starts. Really, that's all I can say given my limited knowledge of your specific situation.

Javier Badia
I can't put them before the loops because the entire script is a loop. This runs in the Blender game engine. So to use the init I just write __init__(velocity_x = 0.03)
Wehrdo
@Wehrdo: Add more code, then. We can't really know what to do if you don't.
Javier Badia
If I were to write the following at the beginning of the script, would it only initialize the velocity variable once, even though it loops through the entire script? __init__(velocity_x = 0.03)
Wehrdo
A: 

An example of using global.

#The velocity of the object
velocity_x = 0.09
velocity_y = 0.03
loc_x = 0
loc_y = 0    

def update_velocity():  
  #If the location of the object is over 5, bounce off.
  global velocity_x, velocity_y
  if loc_x > 5:
    velocity_x = (velocity_x * -1)

  if loc_y > 5:
    velocity_y = (velocity_y * -1)

def update_position():
  global loc_x, loc_y # global allows you to write to global vars
                      # otherwise you're creating locals :)
  loc_x += velocity_x
  loc_y += velocity_y     

#Every frame set the object's position to the old position plus the velocity

while True:
  update_velocity()
  update_position()
  # undoubtedly you do more than this...
  obj.setPosition([loc_x,loc_y,0])

EDIT

I saw an __init__ in some comment. If you're in a class shouldn't you write something like:

self.loc_x += self.velocity_x

and so on, to reference the instance?

extraneon
I should have clarified that loc_x and loc_y are the object's current x and y location. They change depending on the location of the object. I'll try putting this method in the script and seeing if it works.
Wehrdo
In a different environment this would be a very good way to do it. Unfortunately, the Blender Game Engine constantly runs scripts over and over from the beginning to the end. Since you declare velocity_x and velocity_y at the beginning of the script, the game engine will keep going to the top and re-initializing those variables. Also, using the "while" statement in the Blender Game Engine stops all other processes until the while statement is false, which in this case would be never. That would freeze the game.
Wehrdo
+1  A: 

im looking for the answer of the same question. there is one way i coould find.u must click on the "add property" button and add a property in blender UI.for example, oneTime=False.

then in the script write:

if oneTime==False: Do events. oneTime=True

this is the only way i could find.

xxx
+1  A: 

If your python runtime environment is the same every time the script is run try moving your initialization to an exception handler. Like so:

try:
    velocity_x = (velocity_x * -1)
except:
    velocity_x = 0.09

You can also try stuffing the variable into the __main__ module if that doesn't work. Like so:

try:
    __main__.velocity_x = (velocity_x * -1)
except:
    __main__.velocity_x = 0.09

If that doesn't work you'll need something lightweight and built in like the sqlite3 module. I rewrote your entire code snippet:

import sqlite3

#The current location of the object
loc_x = obj.getPosition()[0]
loc_y = obj.getPosition()[1]

c = sqlite3.connect('/tmp/globals.db')
#c = sqlite3.connect('/dev/shm/globals.db')
# Using the commented connection line above instead will be
# faster on Linux. But it will not persist beyond a reboot.
# Both statements create the database if it doesn't exist.

# This will auto commit on exiting this context
with c:
    # Creates table if it doesn't exist
    c.execute('''create table if not exist vectors 
      (vector_name text primary key not null, 
       vector_value float not null,
       unique (vector_name))''')

# Try to retrieve the value from the vectors table.
c.execute('''select * from vectors''')
vector_count = 0
for vector in c:
    vector_count = vector_count + 1
    # sqlite3 always returns unicode strings
    if vector['vector_name'] == u'x':
        vector_x = vector['vector_value']
    elif vector['vector_name'] == u'y':
        vector_y = vector['vector_value']

# This is a shortcut to avoid exception logic
# Change the count to match the number of vectors
if vector_count != 2:
    vector_x = 0.09
    vector_y = 0.03
    # Insert default x vector. Should only have to do this once
    with c:
        c.executemany("""replace into stocks values 
          (?, ?)""", [('x', vector_x), ('y', vector_y)])

#If the location of the object is over 5, bounce off.
if loc_x > 5:
    velocity_x = (velocity_x * -1)
if loc_y > 5:
    velocity_y = (velocity_y * -1)

# Update stored vectors every time through the loop
with c:
    c.executemany("""update or replace stocks set vector_name = ?, 
      vector_value = ?)""", [('x', vector_x), ('y', vector_y)])

#Every frame set the object's position to the old position plus the velocity
obj.setPosition([(loc_x + velocity_x),(loc_y + velocity_y),0])

# We can also close the connection if we are done with it
c.close()

Yes it could be tuned into functions or fancy classes but if that is the extent of what you are doing you don't need much more than that.

freegnu
That adding a property in the blender ui trick sure sounds easier.
freegnu