Need help keeping an object on screen

I’m trying to get a simple side-scrolling shooter setup, but I’m a having some problems keeping the ship bound in the screen. Here’s the details:

1.The camera and ship both have an always: Dloc moving them right, so they move in sync if no directional keys are pressed.

2.The camera has 4 planes parented to it:screentop, screenbottom, screenleft, and screenright. These are the screen bounds that the ship can’t cross. They are invisible and have no collision. A script turns their positions into global variables: g.boundstop, g.boundsbottom, etc.

  1. I hope to to consolidate the key sensors and movement actuators, and setup a variable speed.

The scripts so far:


import GameLogic as g
g.playerPos = g.getCurrentScene().getObjectList()["OBplayer"].getPosition()
g.boundsTop = g.getCurrentScene().getObjectList()["OBscreenTop"].getPosition()
g.boundsLeft = g.getCurrentScene().getObjectList()["OBscreenLeft"].getPosition()

import GameLogic as g
cont = g.getCurrentController()
own = cont.getOwner()

up = cont.getSensor("up")
down = cont.getSensor("down")

moveup = cont.getActuator("moveup")
movedown = cont.getActuator("movedown")

if up.isPositive() and (g.playerPos[2] < g.boundsTop[2]):
    g.addActiveActuator(moveup,1)
if not up.isPositive():
    g.addActiveActuator(moveup,0)
    

The ship won’t go up if it’s above or at the boundsTop, but if it’s moving and the button is held, it goes past it. It doesn’t matter if I move the ship with Dloc, linV or force. Anyone have any thoughts on how I can better structure the script?

I also need a way to keep the ship from being bumped of screen by terrain or enemies. Is there a way to just apply an impulse if the playerPos is >= boundsTop position? (I don’t know how applyImpulse() works just yet.)

Thanks

Change the second script to read like this: (chages in bold)

import GameLogic as g
cont = g.getCurrentController()
own = cont.getOwner()

up = cont.getSensor("up")
down = cont.getSensor("down")

moveup = cont.getActuator("moveup")
movedown = cont.getActuator("movedown")

if up.isPositive() and (g.playerPos[2] < g.boundsTop[2]):
    g.addActiveActuator(moveup,1)
<b>elif up.isPositive() and (g.playerPos[2] &gt;= g.boundsTop[2]):
    g.addActiveActuator(moveup,0)</b>
<b>elif</b> not up.isPositive():
    g.addActiveActuator(moveup,0)

The way you had it, the actuator would never quit until the button was released, but you want it to quit if the button is released OR if the bounds are met.

In this case you can just stop the actuator if the first condition is not true. this would simplify the logic a little bit:

if up.isPositive() and (g.playerPos[2] &lt; g.boundsTop[2]):
    g.addActiveActuator(moveup,1)
<b>else:</b>
    g.addActiveActuator(moveup,0)

Thanks for the tips guys. I got a script working with one motion actuator and a global speed variable, but it only moves one direction at a time. Any thoughts?


import GameLogic as g
cont = g.getCurrentController()
own = cont.getOwner()

up = cont.getSensor("up")
down = cont.getSensor("down")
left = cont.getSensor("left")
right = cont.getSensor("right")

move = cont.getActuator("motion")


if up.isPositive() and (g.playerPos[2] &lt; g.boundsTop[2]):
    move.setDLoc(0,0,g.speed,0)
    g.addActiveActuator(move,1)
else:
    g.addActiveActuator(move,0)
    
if down.isPositive() and (g.playerPos[2] &gt; g.boundsBottom[2]):
    move.setDLoc(0,0,-g.speed,0)
    g.addActiveActuator(move,1)
else:
    g.addActiveActuator(move,0)
    
if left.isPositive() and (g.playerPos[1] &lt; g.boundsLeft[1]):
    move.setDLoc(0,g.speed,0,0)
    g.addActiveActuator(move,1)
else:
    g.addActiveActuator(move,0)

if right.isPositive() and (g.playerPos[1] &gt; g.boundsRight[1]):
    move.setDLoc(0,-g.speed,0,0)
    g.addActiveActuator(move,1)
else:
    g.addActiveActuator(move,0)


Personally, I’d just use four motion actuators.

Yeah, I’ll probably just go with 4 actuators for now. It works fine. Now that I’m learning python, I like to try and get rid of many logic bricks as possible. I might still try and figure it out, maybe have Up Left Down Right set zspeed and yspeed variables, then set the motion actuator with those.

Any idea on the applyImpulse()? I can still get pushed off screen by game objects.

Edit: Here’s the script with one motion actuator. I moved the speed variable onto the ship:


import GameLogic as g
cont = g.getCurrentController()
own = cont.getOwner()

up = cont.getSensor("up")
down = cont.getSensor("down")
left = cont.getSensor("left")
right = cont.getSensor("right")

move = cont.getActuator("motion")
xspeed = 0
zspeed = 0

if up.isPositive() and (g.playerPos[2] &lt; g.boundsTop[2]):
    zspeed = own.speed
    
if down.isPositive() and (g.playerPos[2] &gt; g.boundsBottom[2]):
    zspeed = -own.speed
        
if left.isPositive() and (g.playerPos[1] &lt; g.boundsLeft[1]):
    xspeed = own.speed

if right.isPositive() and (g.playerPos[1] &gt; g.boundsRight[1]):
    xspeed = -own.speed

move.setDLoc(0,xspeed,zspeed,0)
g.addActiveActuator(move,1)

This is just an idea. I do not know if it helps:

You could reset the position of the player with setPosition().

Get the position with pos = getPosition(), then reset the coordinate that exceeds the limit e.g. pos[2] = maxY. After that set the new position with setPosition( pos ).

You need a sensor that triggers this script when the player goes outside the limits. Maybe a collision sensor. Your bounds set to ghost would prevent the limits to have collisions for other objects. (This method would also correct the limits when you move the actor over the limits with keys press).

I have no idea what impact setPosition() on impulses has. You need to find it out.

Does anyone know if there might be a way to calculate the bounds based on the screen or camera size? I was looking at Blendenzo’s cursor script, and thought there might be some solution involving the Rasterizer, or maybe the Camera methods?