issue with vector addition

Hello fellow blender artists!
Ive been using blender for about 2 years now and finally decided to learn python. Ive started teaching myself by trying to fix bge games that were made back in 2.4, 2.5 etc.
I’m having trouble fixing a bug with the main menu that prevents me from moving the selection cursor across the 3 options.
The following is output when i press the up or down keys to scroll down the main menu:

Blender Game Engine Started
Python script error - object 'Plane.003', controller 'menu':
Traceback (most recent call last):
  File "menu", line 19, in <module>
AttributeError: Vector subtraction: (Vector -= int) invalid type for this operat
ion
Python script error - object 'Plane.003', controller 'menu':
Traceback (most recent call last):
  File "menu", line 20, in <module>
AttributeError: Vector addition: (Vector += int) invalid type for this operation


Blender Game Engine Finished


Here are the lines of code that are causing the problem:

if up: pos -= 1
if down: pos += 1

I know it has to do with the fact that you can’t add an integer to a vector, but i’ve been searching online all day and I haven’t found a solution yet. :frowning:

Thanks in advance :smiley:

If you want to add an integer to a Vector (pos is a Vector in this case), you need to specify which axis you want to add it to (x, y, or z). In your case you probably want the z axis.

if up:
    pos.z -= 1
if down:
    pos.z += 1

it didnt work
sorry, i forgot to mention that pos is apparently referring to a keyframe on the timeline

A keyframe is a number. Usually from type float. You would not get a problem adding 1 to a float.
Why do you call a keyframe “pos”? Is it because it is supposed to be “positive” ;)?

Anyway, it would be better to provide more details. You already know the source of the error. But we can’t guess what you want to do.

Sadly, im not the original creator of this game so I wouldn’t know why he/she used certain commands.
However, the game was originally made in 2.4, so a lot of the original code was deprecated.

Here is the code for the main menu with my modifications.

import GameLogic
import math
import mathutils
from mathutils import Vector
g = GameLogic
cont = g.getCurrentController()
own = cont.owner
pos = own.position


keys = cont.sensors["keys"].events


if not keys: keys = []
    


up = [146,1] in keys or [119,1] in keys
down = [144,1] in keys or [115,1] in keys
next = [13,1] in keys or [32,1] in keys


if up: pos -= 1
if down: pos += 1


if pos == 0: pos = 3    
if pos == 4: pos = 1
    
cont.activate(cont.actuators["ipoPos"])


# Enter or space
if next:
    if pos == 1: # 3d Mode
        g.cont.activate(cont.actuators("arenaScene"),1)
        g.gameMode = 0
        
    elif pos == 2: # 2d Mode
        g.cont.activate(cont.actuators("arenaScene"),1)
        g.gameMode = 1
        
    elif pos == 3: # Exit
        g.cont.activate(cont.actuators("quitGame"),1)

What version of Blender are you using? I just added “.z” after pos and tested it using 2.7, and it worked perfectly fine.

im on blender 2.71
also pos isnt referring to a point on the grid, its referring to a point on the timeline for some reason in this script

The code here is functionally incorrect -> GameLogic (bge.logic) does not have a “cont” attribute.
This is closer to what you’re looking for, but without any context, I can’t write much more.


import math
from mathutils import Vector
from bge import logic, events




def close_to(x, y, epsilon=0.001):
	return abs(x - y) <= epsilon




def main(cont):
	own = cont.owner
	pos = own.worldPosition


	keyboard_events = dict(cont.sensors["keys"].events)
	ipo_actuator = cont.actuators["ipoPos"]
	just_pressed = logic.KX_INPUT_JUST_ACTIVATED


	up = just_pressed in (keyboard_events.get(events.WKEY), keyboard_events.get("UPARROWKEY"))
	down = just_pressed in (keyboard_events.get(events.SKEY), keyboard_events.get("DOWNARROWKEY"))
	next = just_pressed in (keyboard_events.get(events.RETKEY), keyboard_events.get(events.SPACEKEY))


	if up:
		pos.z -= 1
		
	if down:
		pos.z += 1


	if pos.z <= 0:
		pos.z = 3    
		
	if pos.z >= 4:
		pos.z = 1
		
	cont.activate(ipo_actuator)


	# Enter or space
	if next:
		if close_to(pos.z, 1): # 3d Mode
			cont.activate(cont.actuators("arenaScene"))
			g.gameMode = 0
			
		elif close_to(pos, 2): # 2d Mode
			cont.activate(cont.actuators("arenaScene"))
			g.gameMode = 1
			
		elif close_to(pos, 3): # Exit
			cont.activate(cont.actuators("quitGame"))

I don’t think it’s a good idea to try and update other people’s games from old versions of Blender unless you are some kind of Blender/python wizard. I wouldn’t even try to update my own games, because even though I knew what I was doing at the time, I sure don’t know now what I was thinking then.

Changing from old versions of Blender can introduce all sorts of unintended changes or completely break old scripts in unpredictable ways.
If you want to learn Python by teaching yourself I’d recommend starting some of your own simple projects to try and do some of the things you commonly do with logic bricks.

The code shows

cont = g.getCurrentController()

. So it is fine, otherwise it would result in another error.

Remarks
Nevertheless this code contains some things that are not nice:

  • importing the module GameLogic as “g” rather than using the the well known name “GameLogic” which is more understandable.
  • using KX_GameObject.position which was deprecated and incorrect even in version “2.4*”
  • using codes as numbers in the sources (e.g. 3, 146). This makes the code hard to understand. There are constants that are much better to read. See BGE API.
  • mapping of the objects position to the function of the menu. This is a real design flaw.
  • checking a float value with == and an integer constant is usually not a good idea as the number precision makes them unequal values in most of the cases. It might have worked in the original application, but mostly because of other side-effects.
  • the code requires comments to explain what the situation is. This usually a sign that the code is unnecessary hard to understand. [There are situations when this is indeed necessary, but not here]

Analysis:
in pre-2.5 the position (better localPosition) returned a list with the coordinates of the position:

[x,y,z]

(since 2.5 it is a mathutils.Vector)

To be honest I never tried to perform a “+=” operation on a list. So I need to check what will happen … it results in a TypeError.

So this code as it is should not even work in 2.4*.

I can only guess that “pos” has a completely different source. It is not a list (2.4-) nor a vector (2.5+). Best bet t is supposed to be


pos = own.localPosition[2]

Solution:
As you wrote this is not your code - I suggest you look for a different menu logic with a better design and a working implementation.

I decided to remove the cursor based menu selection system as it was too complex and go for a simpler key based selection system.

import GameLogic
cont = GameLogic.getCurrentController()


# Enter or space
if bge.events.ONEKEY: # 3d Mode
    cont.activate(cont.actuators["arenaScene"])
    gameMode = 0
        
elif bge.events.TWOKEY: # 2d Mode
    cont.activate(cont.actuators["arenaScene"])
    gameMode = 1
        
elif bge.events.THREEKEY: # Exit
    cont.activate(cont.actuators["quitGame"])
    gamemode = 2

Now i’m having trouble with a different part of the game. (not caused by this)
Should I just ask it here or make another thread?