Pyglet controller object with event lister problem (setting up event-object at __init__ giving runtime error)

Question:

I am trying to get a controller object working using Pyget. I have been following this documentation, but am not sure how to set up button listeners.

This is a pared down version of my code:

#test_2.py
import arcade
import sys
import os
import pyglet

controller__cursor = None

def initiate(maingame_window):
    global controller__cursor
    controller__cursor = CursorControl(maingame_window)

class CursorControl():
    active_cursor_list = [] # (player, cursor_x, cursor_y,  controller_num, colour)
    initiated_controller_namelist = []
    
    joystick_count = 0
    controller_manager = pyglet.input.ControllerManager()
    
    class ActiveController():
        pos_x = 0
        pos_y = 0
        controller_obj = None
        cursor_colour = arcade.color.GREEN
        assigned_player = None
        def __init__(self, controller_obj, assigned_player):
            self.assigned_player = assigned_player
            self.controller_obj = controller_obj
            
            self.controller_obj.open()
            print("openning controller")
            
            self.controller_obj.event = self.on_button_press(self.controller_obj.event)
        
        @controller_obj.event # This throws an error because controller_obj = None, but it is set in __init__
        def on_button_press(controller_obj, button_name):
            print("on_button_press called")
            if (button_name == 'a'): print("a pressed")
            elif (button_name == 'b'): print("b pressed")
    
    def __init__(self, maingame_window):
        all_gamepads = self.get_controllers()
        if (len(all_gamepads) > 0):
            for a_controller_num in self.get_controllers():
                print(f"Connection initial controllers: {a_controller_num}")
                self.connect_new_controller(a_controller_num)
        else:
            self.connect_new_controller(0) # On controller plug-in, add the controller to player 1
    
    # Controller Manager
    @controller_manager.event
    def on_connect(controller):
        print(f"Connected:  {controller}")

    @controller_manager.event
    def on_disconnect(controller):
        print(f"Disconnected:  {controller}")
    
    def get_controllers(self):
        return_list = []
        for a_device in self.controller_manager.get_controllers():
            return_list.append(a_device)
        return return_list
    
    def connect_new_controller(self, controller_obj):
        print("Connecting new controller: " + controller_obj.name)
        screen_w, screen_h = getScreenDims()
        self.initiated_controller_namelist.append(controller_obj.name)
        
        # Controller is opened (controller_obj.open()) in the __init__ of self.ActiveController
        self.active_cursor_list.append(
            self.ActiveController(controller_obj, "Player_Name")
        )

class MainGame(arcade.Window):
    cursor_colour = arcade.color.GREEN
    stage_status = "menu_main"
    player_list = [] # populate this on game selection (or load). It will hole the player info (name, cursor x&y)
    def __init__(self):
        super().__init__(600, 600, title="Trivia Quest")
        self.set_mouse_visible(True)
        # Starting location of cursor
        self.x = 100
        self.y = 100
        
        #print("Initial: " + str(arcade.get_game_controllers()))
        
        initiate(self)
    
    update_tick_count = 0
    def update(self, delta_time): pass
    
    def on_update(self, delta_time):
        self.update_tick_count += 1
        if (self.update_tick_count % 60 == 0): self.on_update_second()
    
    def on_update_second(self):
        pass
        #controller__cursor.on_step(self)
  
    # Creating on_draw() function to draw on the screen
    def on_draw(self):
        arcade.start_render()
        arcade.draw_circle_filled(self.x, self.y, 25, self.cursor_colour)
        
        #arcade.finish_render()
  
    # Creating function to check the position of the mouse
    def on_mouse_motion(self, x, y, dx, dy):
        tq_menu.controller__cursor.mouse_move(x, y, dx, dy)
        self.x = x
        self.y = y
    
    def on_mouse_press(self, x, y, button, modifiers):
        self.cursor_colour = arcade.color.BLUE
    
    def on_mouse_release(self, x, y, button, modifiers):
        self.cursor_colour = arcade.color.GREEN

MainGame()
arcade.run()

And this is the error message:

Traceback (most recent call last):
  File "...test_2.py", line 12, in <module>
    class CursorControl():
  File "...test_2.py", line 19, in CursorControl
    class ActiveController():
  File "...test_2.py", line 34, in ActiveController
    @controller_obj.event # This throws an error because controller_obj = None, but it is set in __init__
AttributeError: 'NoneType' object has no attribute 'event'

I’m not sure how to set @controller_obj.event with controller_obj not as None when that object is set through the init. I’m sure there is something I am missing about this process.

Asked By: Pogmog

||

Answers:

I found out the answer. The listener has to be assigned after the initialisation. It works when the "bind_button_press" function is called to assign the functions. Here is the updated "ActiveController" class, with stick, trigger, dpad, and button listeners:

class ActiveController():
        pos_x = 0
        pos_y = 0
        
        controller_obj = None
        cursor_colour = arcade.color.GREEN
        assigned_player = None
        
        def __init__(self, controller_obj, assigned_player):
            self.assigned_player = assigned_player
            self.controller_obj = controller_obj
            
            self.controller_obj.open()
            
            self.bind_button_press() # Set the assigns to be after the initialisation
            
        def on_trigger_motion(self, device_obj, trigger_name, value):
            if (trigger_name == "righttrigger"):
                print(self.assigned_player + " goes pew pew")
            
        def on_dpad_motion(self, device_obj, left, right, up, down):
            pass
        
        def on_stick_motion(self, device_obj, stick_name, xaxis, yaxis):
            self.pos_x += xaxis
            self.pos_y += yaxis
        
        def on_button_press(self, device_obj, button_name):
            if (button_name == 'a'): 
                print("a pressed")
            elif (button_name == 'b'): 
                print("b pressed")
            
        def bind_button_press(self):
            self.controller_obj.push_handlers(on_button_press=self.on_button_press)
            self.controller_obj.push_handlers(on_stick_motion=self.on_stick_motion)
            self.controller_obj.push_handlers(on_dpad_motion=self.on_dpad_motion)
            self.controller_obj.push_handlers(on_trigger_motion=self.on_trigger_motion)
Answered By: Pogmog
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.