【问题标题】:How to permanently change a variable in a Python game loop如何在 Python 游戏循环中永久更改变量
【发布时间】:2011-02-09 11:06:39
【问题描述】:

我正在制作的游戏中有这个脚本。这将在 Blender 游戏引擎中使用。 Blender 不断地从上到下不断地运行脚本,所以如果我在脚本的开头声明一个变量,它就会不断地被初始化。

#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])

基本上,我的问题是在 if 循环中,我将变量从其原始值更改为其旧值的倒数。但是因为我在脚本开头声明了变量的值,所以速度变量不会停留在我将其更改为的值上。

我需要一种方法来永久更改变量的值或只声明一次。

谢谢!

【问题讨论】:

  • 旁白:“如果循环”不存在。 “如果”不循环。
  • 我认为我们在这里遗漏了一些逻辑。 velocity_x 和velocity_y 的值在结尾和开头肯定是不同的。这一切都包含在一个函数中吗?
  • 如果不显示更多代码,就不可能回答您的问题。如所写,您的代码将正常工作。您的代码中有任何功能吗?你在使用global 语句吗?
  • “if”语句不是循环。整个脚本在游戏过程中循环。该变量在顶部声明,因此每次脚本再次循环时,该变量都会更改回其原始值。
  • 一个小的“pythonic”注释:“velocity_x = (velocity_x * -1)”比“velocity_x *= -1”更漂亮

标签: python variables blender


【解决方案1】:

将velocity_x 和velocity_y 声明放在循环之前。如果您正在使用类,请将它们设置为对象的属性并在其 __init__() 内只初始化一次。

编辑:我不知道 Blender 游戏引擎是如何工作的,但除了让脚本处于大循环之外,应该有一种方法可以在循环开始之前初始化内容。真的,鉴于我对您的具体情况了解有限,我只能说这些。

【讨论】:

  • 我不能把它们放在循环之前,因为整个脚本是一个循环。这在 Blender 游戏引擎中运行。所以要使用初始化,我只需要写 __init__(velocity_x = 0.03)
  • @Wehrdo:然后添加更多代码。如果您不这样做,我们真的不知道该怎么办。
  • 如果我在脚本的开头编写以下内容,它是否只初始化速度变量一次,即使它循环通过整个脚本? __init__(velocity_x = 0.03)
【解决方案2】:

我正在寻找相同问题的答案。我可以找到一种方法。你必须单击“添加属性”按钮并在搅拌机 UI 中添加一个属性。例如,oneTime=False。

然后在脚本中写:

如果 oneTime==False: 做活动。 oneTime=True

这是我能找到的唯一方法。

【讨论】:

    【解决方案3】:

    如果每次运行脚本时您的 python 运行时环境都相同,请尝试将初始化移动到异常处理程序。像这样:

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

    如果不起作用,您也可以尝试将变量填充到 __main__ 模块中。像这样:

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

    如果这不起作用,您将需要一些轻量级的内置功能,例如 sqlite3 模块。 我重写了你的整个代码 sn-p:

    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()
    

    是的,它可以调整为函数或花哨的类,但如果这是你所做的事情的范围,那么你不需要更多。

    【讨论】:

    • 在搅拌机 ui 技巧中添加属性听起来更容易。
    【解决方案4】:

    要处理脚本代码的连续循环,您需要一个写在代码之外的值。否则无法正常工作。你的脚本应该如何知道它之前已经运行过?以下代码在 Blender 2.6 和 2.7 系列中运行:

    可能性一:Blenders 全球词典。 添加一个子字典(也可以为空):

    bge.logic.globalDict['mysubdictionaryName'] = { 'namestring' : False}
    

    您可以像这样保存值: bge.globalDict['mysubdictionaryName'] = myValue.

    可能性2:对象属性 a) 使用 python:

    myObject = bge.logic.getCurrentController().owner
    
    myObject['myproperty_named_has_run_before'] = True
    

    b) 使用 Logicbricks 并在 Logic-editor 中添加属性

    在您的情况下,您应该使用 objectproperties,因为使用 globalDict,当多个对象通信或您需要将数据带到另一个游戏场景时。

    【讨论】:

    • 天哪,这是一个迟到的回应!显然现在对我没有多大用处,但仍然是正确的。如果你很好奇,这就是项目的内容:davidawehr.com/projects/puck.html
    【解决方案5】:

    使用全局的示例。

    #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])
    

    编辑

    我在一些评论中看到了__init__。如果你在上课,你不应该写这样的东西:

    self.loc_x += self.velocity_x
    

    等等,引用实例?

    【讨论】:

    • 我应该澄清一下 loc_x 和 loc_y 是对象的当前 x 和 y 位置。它们根据对象的位置而变化。我会尝试将此方法放入脚本中,看看它是否有效。
    • 在不同的环境中,这将是一个非常好的方法。不幸的是,Blender 游戏引擎从头到尾不断地运行脚本。由于您在脚本的开头声明了velocity_x 和velocity_y,游戏引擎将继续返回顶部并重新初始化这些变量。此外,在 Blender 游戏引擎中使用“while”语句会停止所有其他进程,直到 while 语句为假,在这种情况下永远不会。那会冻结游戏。
    • 要处理脚本代码的连续循环,您需要一个写在代码之外的值。否则无法正常工作。你的脚本应该如何知道它之前已经运行过?
    猜你喜欢
    • 2023-02-07
    • 2012-08-09
    • 2011-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多