Detect Position Loop

Hello. I am a bit new to Panda3D. Below is a little game I have been working on. It is similar to Subway Surfers or Temple Run. I would like an obstacle to appear in a random X position and move to another random X position when the interval starts again. Currently, I have the obstacle start when the “o” key is pressed. I was thinking of a loop to check whether or not the position is behind the player. If it is, the X position will be randomly generated again and the interval restarts. How can I make this loop? I know it may be pretty obvious, yet I still can’t find it. Thanks! :smiley:

I made the trail move with an interval to make it simulate running. I was having trouble with a looping path.

from direct.showbase.ShowBase import ShowBase
from direct.task import Task
from direct.actor.Actor import Actor
from direct.showbase import DirectObject
from panda3d.core import *
from direct.gui.DirectGui import *
from direct.interval.IntervalGlobal import Sequence
from panda3d.core import Point3
import sys
from random import randint

print("Loading...")

class MyApp(ShowBase, DirectObject.DirectObject):
	def __init__(self):
		ShowBase.__init__(self)
		
		self.gear = loader.loadModel('phase_9/models/char/gearProp.bam')
		self.gear.setP(90)
		self.gear.setScale(0.20)
		self.gear.reparentTo(self.render)
		self.gear.show()
		
		base.setBackgroundColor(0,0,0)
		
		self.music = loader.loadMusic("bg_music.mp3")
		self.music.setLoop(1)
		self.music.play()
		
		self.title = OnscreenText(text="Mickey Run - Dev Edition", style=1, fg=(1,1,1,1), pos=(0.87,-0.95), scale = .07)
		self.title = OnscreenText(text="Music by Yorke", style=1, fg=(1,1,1,1), pos=(-0.87,-0.95), scale = .07)
		
		self.enviroment = loader.loadModel('path.egg')
		self.enviroment.setScale(2.5)
		self.enviroment.setY(50)
		self.enviroment.reparentTo(render)
		
		self.den = 0
		self.model = "phase_3/models/char/mickey-1200.bam"
		
		self.mouse = Actor("phase_3/models/char/mickey-1200.bam", {"walk": "phase_3/models/char/mickey-walk.bam", "run": "phase_3/models/char/mickey-run.bam", "wait": "phase_3/models/char/mickey-wait.bam"})
		self.mouse.reparentTo(self.render)
		self.mouse.loop("wait")
		
		self.accept('arrow_up', self.animationRun)
		self.accept('escape', self.escape)
		self.accept('arrow_left', self.goLeft)
		self.accept('arrow_right', self.goRight)
		self.accept('h', self.hat)
		self.accept('b', self.backgroundBlack)
		self.accept('w', self.backgroundWhite)
		self.accept('control', self.jump)
		self.accept('o', self.makeObstacle)
		self.accept('f', self.fogOff)
		
		
		self.fog = Fog('distanceFog')
		self.fog.setColor(0, 0, 0)
		render.setFog(self.fog)
		self.fog.setExpDensity(.08)
		
		base.camera.reparentTo(self.mouse)
		base.camera.setPos(0, -5, 1)
		base.camera.setP(-10)
		base.camera.hide()
		base.oobe()
		base.setFrameRateMeter(True)
		
		self.x = self.mouse.getX()
        
	def animationRun(self):
		self.mouse.loop("run")
		self.current_frame = self.mouse.getCurrentFrame('run')
		self.movement = self.enviroment.posInterval(2, Point3(0, -25, 0), startPos=Point3(0, 25, 0))
 
		self.movement = Sequence(self.movement, name="pandaPace")
		self.movement.loop()
		
		
	def goLeft(self):
		if self.mouse.getX() == 0 or self.mouse.getX() == 5:
			go_left = self.mouse.getX() -5
			self.mouse.setX(go_left)
			print self.mouse.getX()
		elif self.mouse.getX() == -5:
			self.mouse.setX(-5)
			print self.mouse.getX()
			
	def goRight(self):
		if self.mouse.getX() == 0 or self.mouse.getX() == -5:
			go_right = self.mouse.getX() +5
			self.mouse.setX(go_right)
			print self.mouse.getX()
		elif self.mouse.getX() == 5:
			self.mouse.setX(5)
			print self.mouse.getX()
		
	def jump(self):
		self.jump_up = self.mouse.posInterval(0.25, Point3(self.mouse.getX(), self.mouse.getY(), 4), startPos=Point3(self.mouse.getX(), self.mouse.getY(), 0))
		self.jump_down = self.mouse.posInterval(0.25, Point3(self.mouse.getX(), self.mouse.getY(), 0), startPos=Point3(self.mouse.getX(), self.mouse.getY(), 4))
		self.jump = Sequence(self.jump_up, self.jump_down, name="jump")
		self.jump.start()
		
			
	def hat(self):
		self.head = self.mouse.find('**/joint_pupilR')
		self.hat = loader.loadModel("phase_4/models/accessories/tt_m_chr_avt_acc_hat_wizard.bam")
		self.hat.setScale(0.35)
		self.hat.setY(-0.10)
		self.hat.setZ(0.5)
		self.hat.setHpr(180, -20, 0)
		self.hat.reparentTo(self.head)	
	
	def makeObstacle(self):
		self.randPos = randint(1, 3)
		if self.randPos == 1:
			self.gear.setX(-5)
		elif self.randPos == 2:
			self.gear.setX(0)
		elif self.randPos == 3:
			self.gear.setX(5)
			
		self.gMove1 = self.gear.posInterval(2, Point3(self.gear.getX(), -25, 1), startPos=Point3(self.gear.getX(), 25, 1))
		self.gMove = Sequence(self.gMove1, name="gMove")
		self.gMove.start()
		
		if self.gear.getY() == 0:
			self.randPos = randint(1, 3)
			if self.randPos == 1:
				self.gear.setX(-5)
			elif self.randPos == 2:
				self.gear.setX(0)
			elif self.randPos == 3:
				self.gear.setX(5)
			self.gMove.start()
			
	
	def backgroundBlack(self):
		base.setBackgroundColor(0,0,0)
		
	def backgroundWhite(self):
		base.setBackgroundColor(1,1,1)
		
	def fogOff(self):
		self.render.clearFog()
			
	def escape(self):
		sys.exit()

app = MyApp()
app.run()

I’m inclined to recommend using a task rather than a loop: unless you provide some way out of the loop (such as by giving it its own thread and then yielding as appropriate, I think), a loop seems likely to stop your program until the object moves behind the player, as execution (presumably) doesn’t leave the loop until that condition is met; if your object’s position is updated outside of the loop, then this may never happen. A task, on the other hand, executes a method or function either every frame or at specified intervals, which seems as though it should serve your purposes well.

The manual should instruct you in how to use tasks, starting with this page; I believe that a task is also used in the tutorial (which should also be found in the manual).

(Note that while the above-linked section on tasks show them calling functions that are not members of a class, you can also have them call class-methods, I believe: just provide them with .methodName instead of just , where is a reference to the relevant object (or “self” in the case of a task being set up from within the object), and is, well, the name of the method.)