Comparable function to PyGame's Width/Height function for detecting objects at edge of window

As far as I know, there’s two functions in BGE called getScreenPosition() and getScreenRay(). The first works by getting the pixel position relative to the camera, and the second works be getting the object hit position relative to in-world units. What I’m wondering is, how would I make a function using these comparable to PyGame’s functions for Width/Height, such as:

import pygame, math
size = width, height = 800, 600
objspeed = [1, 1]

screen = pygame.display.set_mode(size)
events = pygame.event.get()

obj = pygame.image.load("\\obj.png")

while 1:
    objrect = objrect.move(objspeed)
    if objrect.left < 0 or objrect.right > width:
        objspeed[0] = -objspeed[0]
    if objrect.top < 0 or objrect.bottom > height:
        objspeed[1] = -objspeed[1]

    screen.fill(0, 0, 0)
    screen.blit(obj, objrect)
    pygame.display.flip()

Where the it’s calling the “width” and “height” variables it’s getting from the window width and height to figure out of the object has hit the edge of the window display area, in order to bounce it back in the other direction. In BGE I’ve tried the following code, but it just makes the sphere fly off the screen and never come back:

import bge
import math
import Rasterizer
    
cont = bge.logic.getCurrentController()
scene = bge.logic.getCurrentScene()
own = cont.owner

winWidth = bge.render.getWindowWidth()    
winHeight = bge.render.getWindowHeight()        
Sphere  = scene.objects['Sphere']
Camera = own.scene.active_camera

ballScreenPosition = Camera.getScreenPosition(Sphere)
ballDetect = Camera.getScreenRay(*ballScreenPosition, 100)

if ballDetect == Sphere:
    print("Lookit the priddy burdy")
    
if "init" not in own:
    own["ballXSpeed"] = True
    own["ballYSpeed"] = True
    own["init"] = True
        
if ballPosition > 1.0:
    own['ballXSpeed'] = False
if ballPosition < 0.0:
    own['ballXSpeed'] = True
if ballPosition > winHeight:
    own['ballYSpeed'] = False
if ballPosition < winHeight:
    own['ballYSpeed'] = True
        
if own['ballXSpeed'] == True:
    Sphere.applyMovement((0.1, 0.0, 0.0), True)
if own['ballXSpeed'] == False:
    Sphere.applyMovement((-0.1, 0.0, 0.0), True)
if own['ballYSpeed'] == True:
    Sphere.applyMovement((0.0, 0.1, 0.0), True)
if own['ballYSpeed'] == False:
    Sphere.applyMovement((0.0, -0.1, 0.0), True)

Am I doing something wrong, or are these functions not comparable?

https://docs.blender.org/api/blender_python_api_current/bge.types.KX_Camera.html#bge.types.KX_Camera.getScreenPosition

I think you want this?

https://docs.blender.org/api/blender_python_api_2_77_1/bge.render.html#bge.render.getWindowWidth

https://docs.blender.org/api/blender_python_api_2_77_1/bge.render.html#bge.render.getWindowHeight

side note - why not use a box collider and rays?
vel = object.worldLinearVelocity.reflect(rayHitNormal)

import bge
import time

ball = own.scene.objects['Ball']
if 'Time' not in own:
    own['Time']=time.time()

timestep = time.time - own['Time']
end = ball.worldPosition+(ball.worldLinearVelocity*(timestep))
ray = ball.rayCast(end, ball.worldPosition, 0, "", 0,0,0)
if ray[0]:
    ball.worldLinearVelocity = ball.worldLinearVelocity.reflect(ray[2])
    ball.worldPostion= ray[1]+ own.worldLinearVelocity.normalized()*ball['radius']
own['Time']=time.time()

edit - untested code but should work

getScreenPosition(obj) returns a tuple containing the normalized x,y coords of the object.
(0.0,0.0) is top left and (1.0,1.0) is bottom right. (0.5, 0.5) is center.

getWindowWidth() and getWindowHeight() both return pixels as in the resolution you’re most familiar with (800x600, 1920x1080, etc.)

you can easily convert the normalized coords to pixels by multiplying your normalized value by the corresponding window value. Example:

ballPosX = int(ballScreenPosition[0] * winWidth) # Pixel position
ballPosY = int(ballScreenPosition[1] * winHeight) # Pixel position

Also look at any errors in the console regarding ‘ballPosition’ as you are not declaring it anywhere. That block of code may be a good place for ballPosX and ballPosY

I am using ball.worldPosition and using linear velocity,

I will provide a small example if you wish.

i was referring to the original poster’s code and why it is not working for him. your code is a complete redesign of what he was asking about

Oh, sorry about that. I hadn’t just copied and pasted and wrote that by hand. I added your suggestion for “ballPosX/Y” and that allowed it to work. Thank you. I also realized I had messed up the Y and Z directions in world directions versus view directions from the camera… Anyways, now it bounces around the screen as intended. The code as follows for anyone interested in the future:

import bge
import math
import Rasterizer
    
cont = bge.logic.getCurrentController()
scene = bge.logic.getCurrentScene()
own = cont.owner

winWidth = bge.render.getWindowWidth()    
winHeight = bge.render.getWindowHeight()        
Sphere  = scene.objects['Sphere']
Camera = own.scene.active_camera

ballScreenPosition = Camera.getScreenPosition(Sphere)
ballPosX = int(ballScreenPosition[0] * winWidth)
ballPosY = int(ballScreenPosition[1] * winHeight)
ballDetect = Camera.getScreenRay(*ballScreenPosition, 100)

if ballDetect == Sphere:
    print("Lookit the priddy burdy")
    
if "init" not in own:
    own["ballXSpeed"] = True
    own["ballYSpeed"] = True
    own["init"] = True
        
if ballPosX > winWidth:
    own['ballXSpeed'] = False
if ballPosX < 0:
    own['ballXSpeed'] = True
if ballPosY > winHeight:
    own['ballYSpeed'] = False
if ballPosY < 0:
    own['ballYSpeed'] = True
        
if own['ballXSpeed'] == True:
    Sphere.applyMovement((0.1, 0.0, 0.0), True)
if own['ballXSpeed'] == False:
    Sphere.applyMovement((-0.1, 0.0, 0.0), True)
if own['ballYSpeed'] == True:
    Sphere.applyMovement((0.0, 0.0, 0.1), True)
if own['ballYSpeed'] == False:
    Sphere.applyMovement((0.0, 0.0, -0.1), True)
1 Like

excellent. glad it’s working :slightly_smiling_face: