Input Class

I’m having issues moving the model from the UserInputClass, it is accepting keypresses and printing the statements but how to access the model? I tried importing the classes but it did not work.

This is my main.py file.

from direct.showbase.ShowBase import ShowBase
from direct.showbase import DirectObject
from direct.task.Task import Task 
from panda3d.core import *
from direct.gui.OnscreenImage import OnscreenImage
from direct.gui.OnscreenText import OnscreenText
from direct.gui.DirectGui import *
#from UserInputControl import *
from direct.showbase.ShowBase import ShowBase

import sys

class Application(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        keys = Keys()
        
        self.firstModel = Actor("./models/test.x", {"Run":"./models/test.x"})
        self.firstModel.loop("Run")
        # Load movie and its sound (if it has sound).
        self.movie = self.loader.loadTexture("videos/loading_screen.ogm")
        self.sound = self.loader.loadSfx("videos/loading_screen.ogm")

        # Make a plane to play the movie on.
        self.cm = CardMaker("plane")
        self.cm.setFrame(-1, 1, -1, 1)

        # Render that plane to the render2d for Panda.
        self.plane = self.render2d.attachNewNode(self.cm.generate())

        # Load movie into the texture plane.
        self.plane.setTexture(self.movie)

        # This can prevent squashing or distorting of the video.
        self.plane.setTexScale(TextureStage.getDefault(), self.movie.getTexScale())

        # 0 means do not loop infinitely.
        self.movie.setLoop(0)

        # If it has sound, synchronize it to the video.
        self.movie.synchronizeTo(self.sound)

        # Will set the Sound to loop.
        self.sound.setLoopCount(0)
        # Play the sound.
        self.sound.play()

        # Schedule bg image to show 10 seconds later.
        taskMgr.doMethodLater(1, self.loadImageAsPlane, "ImageLoader")
        

        """ To do, add more commands """
        #completed now to make it work??

        """ To do, implement text below model """
        #self.background_text = "Health"
        #self.backgroundText = OnscreenText(self.background_text, pos = (0.95,-0.95) , 
                                     # scale = 0.07, fg = (1,0.5,0.5,1), align = TextNode.ACenter, 
                                     # mayChange = 1)
        
    def loadWorld(self):
        #self.background_text = "Thy journey has begun..."
        #self.backgroundText.setText(self.background_text)

        # Remove the buttons and the background image.
        self.newGameButton.destroy()
        self.loadSavedGameButton.destroy()
        self.background.removeNode()


        # Loads and renders the model.
        self.background.removeNode()
        self.firstModel.reparentTo(self.render)
        #self.setModelPosition()
        self.firstModel.setScale(0.75, 0.75, 0.75)
        self.firstModel.setPos(0, 50, 0)
        #self.firstModel.setTexture(self.firstTexture)
        
        # Will stop the sound if the button is pressed.
        self.sound.stop()
		
	#def setModelPosition(self, x=0, y=0, z=0):
		#self.firstModel.setPos(x,y,z)	
    def loadImageAsPlane(self, task): 
	# Loads image and puts it onscreen. 
        self.background = OnscreenImage(parent=render2d, image='images/Fireworks.jpg')

        # Let's add a button..
        self.newGameButton = DirectButton(text = ("New Game", None, None, None),
                                   pressEffect = 1, scale = .05, command = self.loadWorld)

        self.loadSavedGameButton = DirectButton(text = ("Load Game", None, None, None),
                                   pressEffect = 1, scale = .05, command = self.loadWorld)
        
        self.newGameButton.setPos(-1,1,-0.1)
        self.loadSavedGameButton.setPos(-1,1,-0.2)
        
        # Removes Intro Movie.
        self.plane.removeNode()
        

        
# Assign the class to a variable.        
app = Application()
# And finally, run it!!
app.run()

And this is my user input class:

from main import Application
from direct.showbase import DirectObject
from direct.task.Task import Task 
from panda3d.core import *
from direct.gui.OnscreenImage import OnscreenImage
from direct.gui.OnscreenText import OnscreenText
from direct.gui.DirectGui import *
from direct.actor.Actor import Actor
import sys
from pandac.PandaModules import RenderState


class Keys(DirectObject):
	def __init__(self):
                
		self.isTyping = False
		self.keyMap = {"mvUp":0, "mvDown":0, "mvLeft":0, "mvRight":0}
		
		self.accept("escape", sys.exit)
		
		self.accept("w", self.setKey, ["mvUp", 1])
		self.accept("s", self.setKey, ["mvDown", 1])
		self.accept("a", self.setKey, ["mvLeft", 1])
		self.accept("d", self.setKey, ["mvRight", 1])
		
		self.accept("w-up", self.setKey, ["mvUp", 0])
		self.accept("s-up", self.setKey, ["mvDown", 0])
		self.accept("a-up", self.setKey, ["mvLeft", 0])
		self.accept("d-up", self.setKey, ["mvRight", 0])
		
	def setKey(self, key, value):
		if not self.isTyping:
			print "why did you call me? I serve no purpose, also you pressed %s \n" %key
			self.keyMap[key] = value
			print self.keyMap

Any help would be aprpeciated thanks :slight_smile:

Hi, welcome to the forums! I’m not sure I’ve got what you’re asking for, excuse me if I’m wrong. Do you want to use firstModel from Keys? In that case, you should import the module which contantains Application’s instance in the module which contains Keys (e.g. import ModuleWhichContainsApp, then you could acces it with ModuleWhichContainsApp.app.firstModel). But this won’t work since it would introduce a cyclic referencing between modules, so you should organize your modules in a better way.

Yea, thats my problem. I load model in Application and when the user presses a key, the Key class accepts it and changes the position of the model that was loaded in Application. I’m probably gonna need help rewriting the classes but I’m not sure where to begin.

First, declare the purposes of every class and be as descriptive and detailed as possible (best describe those in docstrings). If you notice that one class does more than one thing then it might be a good idea to split it.
For example your Keys class does one thing: convert key events in booleans that can be polled. That’s a good thing. Further more it defines “actions” that are assigned to each key. If this is a good thing depends on the purpose this class should serve. If it’s meant to control exactly one thing, then it’s okay to be specific on the actions. On the other hand, if you’d like to once use the same class for a car and a human (after each other), then the class might be too specific for general movement.

Here is a random solution:
Write a class that is meant for one specific state in the game, e.g. “walking”, that accepts all keys associated with that state and which converts the keys into actions as your current Keys class does. Let’s name that class WalkingInput.
Second, make a class WalkingActor, which has a referenc eto the PandaNode (model/actor) and a few functions that control the walking of a model/actor. There could be methods like jump(), walkTowards(), run() etc. Now you have a place where actions are triggered and a place where code for specific actions is defined. What’s missing is a place where you map the input actions to function calls. This could be either in your WalkingActor which holds an instance of WalkingInput and looks it up every frame (task function in WalkingActor), doing actions as requested. OR you could write a third class named WalkingActorController which does that. Where you instantiate what class and what class “knows” of each other is an advanced topic and many variants work. You only need to stick to a particular design pattern.