How to constantly change a variable in a Python game loop
I have this script in a game I am making. This will be used in the Blender game engine. Blender is constantly running scripts from top to bottom, so if I declare a variable at the beginning of the script, it keeps getting 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 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 am changing the variable from its original value to the reverse of its old value. But since I declare the value of the variable at the beginning of the script, the speed variables don't stay where I am changing it to.
I need a way to constantly change the value of a variable or declare it only once.
Thanks!
a source to share
To handle a continuous loop through your scripting code, you need a value that is written outside of the code. Otherwise it won't work. How does your script know that it has been run before? The following code works with Blender 2.6 and 2.7:
Feature 1: Global Blender Dictionary . add a subheading (can also be empty):
bge.logic.globalDict['mysubdictionaryName'] = { 'namestring' : False}
you can save these values
bge.globalDict['mysubdictionaryName'] = myValue
.
Possibility 2: Objectproperty a) with python:
myObject = bge.logic.getCurrentController().owner myObject['myproperty_named_has_run_before'] = True
b) Use Logicbricks and Add Properties inside the Logic Editor
In your case, you have to use objectproperties because globalDict is used when multiple objects are exchanging data or you need to take data into another game.
a source to share
Place ads velocity_x
and velocity_y
before the cycle. If you use classes, make them attributes of the object and integrate them only once, inside it __init__()
.
EDIT: I don't know how the Blender game engine works, but in addition to having a script in the big loop, there must be a way to initialize stuff before the loop starts. Indeed, all I can say given my limited knowledge of your particular situation.
a source to share
im looking for an answer to the same question. there is one way i can find. You need to click the "add property" button and add the property to the blender user interface. For example oneTime = False.
then in your script write:
if oneTime == False: Do events. Disposable = True
This is the only way to find.
a source to share
If your python runtime is the same when you run your script, try moving the initialization to your exception handler. For instance:
try:
velocity_x = (velocity_x * -1)
except:
velocity_x = 0.09
You can also try populating the variable in the module __main__
if that doesn't work. For instance:
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 the whole piece of code:
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 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 can be customized to functions or cool classes, but if that's what you are doing, you don't need much more.
a source to share
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 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
In some of the comments I've seen __init__
. If you don't have to write something like:
self.loc_x += self.velocity_x
and so on to reference an instance?
a source to share