Keep Main Character on Screen

Hello,
I’m new. I’ve tried searching a few places for this but haven’t been able to figure it out.
I’m sure it’s simple but I can’t seem to find it.

My “main character” is a ball that rolls around in the XY plane using the accelerometer.
The stage is larger than the device screen.

How do I keep the ball on screen?

Thanks in advance!

[import]uid: 207525 topic_id: 34408 reply_id: 334408[/import]

I deleted my post after re-reading your question.

I think you want to implement a camera view that tracks your ball across the stage while possibly having the ball stay in the center of the screen. Your stage would actually be moving.

I’ve been using perspective.lua, by CalebP, which is found in the Community Code Exchange.

Link to perspective.lua

It’s a great module to implement a camera view.

Nail [import]uid: 106779 topic_id: 34408 reply_id: 136727[/import]

An additional note, if you’re using physics: whatever solution you use, if it involves moving display groups around, and you have your ball and various walls/boundaries/whatever in different groups, remember that you can’t shift those groups independently of each other or you’ll misalign the collision detection system and receive improper collisions.

Brent [import]uid: 200026 topic_id: 34408 reply_id: 136746[/import]

Thanks xnailbender and Brent,

I believe the perspective module is what I need but I am having some trouble getting it to work.
I don’t get any errors… but the ball still falls off the screen.
Here is my code.

[code]
local physics = require(“physics”);
physics.start();
local perspective = require(“perspective”)
local camera=perspective.createView()

local ballObject1 = display.newImageRect (“ballobject.png”,42,42)
ballObject1.x = 200
ballObject1.y = 200
physics.addBody( ballObject1, “dynamic”, { density=1.0, bounce=0.1, friction=0.15, radius=21} )

local function onTilt( event )
physics.setGravity( 10 * event.xGravity, -10 * event.yGravity )
end

Runtime:addEventListener( “accelerometer”, onTilt )

camera:add(ballObject1, 4, false)
camera:setBounds(0,480,0,480)
camera:track() [import]uid: 207525 topic_id: 34408 reply_id: 136788[/import]

Setting physics via a Runtime listener has got to be a poor choice performance-wise.

Have you tried just adding event Gravity to your ball ?

local function onTilt( event )  
 ballObject1.x = ballObject1.x + event.xGravity  
 -- use event.yGravity if you're in landscape mode  
end  

To keep the ball on screen, I’d place 4 static rectangles on the edges of your screen (or stage if it is a scrolling game. And then for scrolling, use the camera approach. [import]uid: 186251 topic_id: 34408 reply_id: 136806[/import]

That’s a nice suggestion Sam.

dpham, I didn’t run your code, but I think I see a problem. You haven’t told the camera to track your ball.

try to change this line and assign the ball as the object the camera tracks.

camera:add(ballObject1, 4, true)  

This should get you started.

FYI, getting the camera view to work can be tricky.

I’m not sure of your “stage” size, but I don’t think you’ve got your camera:setBounds properly set.

I think this is how it works…

By setting the x1 value to “0”, you are telling the camera to NOT track the ball for negative x values (off the left side of the screen).

By setting the x2 value to “480” your are tell the camera to STOP tracking the ball if it goes beyond the right edge of the screen. Same thing goes for the y1 and y2 values.
Experiment with the bounds values.

Maybe try this and look for a difference in behavior.

camera:setBounds(-1000, 1000, -1000 , 1000)  

Hope this helps,

Nail

[import]uid: 106779 topic_id: 34408 reply_id: 136815[/import]

Nice to know someone uses Perspective :slight_smile:

The setBounds function actually simply checks if the object is past the bounds. So setting 0 as the first value for the bounds means as long as the object.x > 0, track it. This means the camera will have a one-half of the screen size to the left of the 0 X point. If you want the object to track perfectly and the screen to stop and show nothing behind the 0 X point, add half the screen size to the bounds.

Here’s an example:
https://www.dropbox.com/s/1661np6bxy8n9t4/diagram.png

Even though the object is at 0,0 X and Y, the camera’s still showing off the screen.

Caleb [import]uid: 147322 topic_id: 34408 reply_id: 136942[/import]

Hey Caleb,

a BIG thanks for “perspective”, I should submit my next game in a couple of weeks, perspective has helped me so much and is my camera view.

I was never able to figure out how to “dampen” the view. I see you got variables declared to handle this, but never implemented them in the module.

My game runs runs smooth @ 60 FPS as is, but think a 1/2 second dampen or maybe even a second + of dampening the movement would improve the smoothing.

Any thoughts on how to easily do this?

Nail [import]uid: 106779 topic_id: 34408 reply_id: 136968[/import]

What exactly do you mean by “dampen”?

C [import]uid: 147322 topic_id: 34408 reply_id: 136985[/import]

Thanks for the recommendations everyone. The new gravity method works fine but I still can’t seem to get the camera to work. The ball still falls off the screen instead of the camera following the ball.

[code]
local function onTilt( event )
ballObject1.x = ballObject1.x + event.yGravity
end

Runtime:addEventListener( “accelerometer”, onTilt )

camera:add(ballObject1, 8, true)

camera:setBounds(1000,0,1000,0)
camera:track()
–for some reason if i setBounds(0,1000,0,1000) then the ballObject1 locks into place and won’t --budge… I’ve played around w/ setBounds a bit and it doesn’t seem to help.

[import]uid: 207525 topic_id: 34408 reply_id: 136997[/import]

Hey Caleb,

I guess I’m trying to describe “easing” the camera view’s tracking as it follows the object slightly.

A damping of the camera’s view, instead of being rigidly locked onto the object.

I saw these variables in the module and thought you had possibly experimented with damping.

view.damping=0
view.prevX, view.prevY=0, 0
view.x2, view.y2=0, 0

My game is a precision platform jumper and I thought if I could slightly slow down the tracking for jumps of less than 100 pixels it might possibly improve the user’s experience.

If the game character jumped 100 pixels, it would possibly move 50 pixels above the screen center for a moment before aligning to the screen center again.

I guess I’m trying to make the camera’s tracking less rigid for smaller vertical movements.

Thanks for even thinking about it,

Nail

[import]uid: 106779 topic_id: 34408 reply_id: 136998[/import]

Hey dpham,

I believe the camera is working when the ball won’t seem to “budge”.

I’m guessing the camera is keeping the ball in the center of the screen as it is actually rolling around.

I could be wrong, but try this. Add something, a vertical line or a letter to your “ballobject.png” and I’m thinking you will see it rotating as it rolls, while the camera keeps it centered on the screen.

You may want to add a background image to your “stage” so you can see the illusion of the ball moving across it. I’m still not sure how big the stage is that you would like to use. I’m guessing you will have to create a function to keep the ball “on” the stage so it doesn’t roll off or drop through.

I’m also wondering what you are rolling your ball on? Have you created a static physics “floor” or a “platform” that the ball rolls on?

It would probably be best of you posted your entire code, I’m just guessing here.

Hope this helps,

Nail

[import]uid: 106779 topic_id: 34408 reply_id: 137004[/import]

@dphan: I think xnailbender has the answer to your problem - the one about not budging. When you don’t have any scenery, the object can appear to not be moving.

@xnailbender: Yes, that was an “invisible” core update I made to support that in the future. That’s simplicity in it’s utmost :slight_smile: to make. I’ve even done it before. I’ll update it in a while. [import]uid: 147322 topic_id: 34408 reply_id: 137008[/import]

Caleb…Thanks for help, I’ll be looking for the update to play with.

I downloaded your latest version of perspective from dropbox, I see you’ve made a few changes. The camera:destroy() has a new iteration. I also noticed the camera:remove(obj) function is missing. I actually use this function a lot and think other users would find it handy if they need it. I did modify the original slightly incase the object didn’t exist which kicked an error.

function view:remove(obj)  
 if obj ~= nil and layer[obj.layer] ~= nil then  
 layer[obj.layer]:remove(obj)  
 else  
 end  
 end  

I don’t mean to hijack the thread, but the perspective info is important here IMO.
FWIW, it would probably be helpful if you could make older versions available and re-label the new versions: 1.2 etc.

Thanks again,

Nail
[import]uid: 106779 topic_id: 34408 reply_id: 137056[/import]

dpham… since I was shooting in the dark, I decided to work up some example code of your issue since I have never played with imput from the accelerometer before and really didn’t understand what I was talking about.

I replaced the listener function. When I left ballObject1.x = ballObject1.x + yGravity

I could get the ball to “slide” down the platform, but it didn’t roll. LOL

So I have applied physics force to the object and it works as expected I believe.

Build this code and load it onto your device, it works with iOS as is if build.settings is set to landscape view.

You can play with all the parameters, I think it’s cool how the ball spins, as if a tire on ice, to gain traction when the device is tilted.

[code]–dpham Ball Roll project

local perspective = require(“perspective”)

local physics = require(“physics”);

local defaultWidth = 480
local defaultHeight = 320
local displayWidth = display.viewableContentWidth
local displayHeight = display.viewableContentHeight
local yMargin = 20
local centerX = defaultWidth/2;
local centerY = defaultHeight/2;

physics.start();
physics.setScale( 60 ) --was 60 – a value that seems good for small objects (based on playtesting)
physics.setGravity( 0, 9.8 )

local BallObjectCollisionFilter = { categoryBits = 1, maskBits = 3 }
local FloorCollisionFilter = { categoryBits = 2, maskBits = 1 }

local FloorGroup = display.newGroup()

local camera
local ballObject1

local function onTilt( event )
ballObject1:applyForce( 8 * event.yGravity)
end

local function buildStage()
camera=perspective.createView()

ballObject1 = display.newImageRect (“ballobject.png”,42,42)
ballObject1.x = 200
ballObject1.y = 50

physics.addBody( ballObject1, “dynamic”, { density=10.0, bounce=0, friction=.25, radius=21, filter = BallObjectCollisionFilter} )
ballObject1.linearDamping = .3

local FloorShape = { -240,-7, 240,-7, 240,7, -240,7 }
local FloorBody = { density=1, friction=.5, bounce=0, shape = FloorShape, filter = FloorCollisionFilter }

local FloorDemo = display.newRect( 0, 0, 480, 10 )
camera:add(FloorDemo, 2, false)
physics.addBody(FloorDemo, “static”, FloorBody)
FloorDemo.x = centerX
FloorDemo.y = centerY + 155
FloorDemo:setFillColor(50, 190, 235 )
FloorDemo.alpha = 1
FloorDemo.isVisible = true
FloorDemo.alpha = 1
FloorDemo.ID = “Floor”
FloorDemo.isBodyActive = true

Runtime:addEventListener( “accelerometer”, onTilt )

camera:add(ballObject1, 4, true)

camera:setBounds(-1000, 1000, -1000 , 1000)
–camera:setBounds(0,480,0,480)
camera:track()
end

local function reset(event)
if event.phase == “ended” then
camera:destroy()
buildStage()
end
end

local TextGroup = display.newGroup()

local Reset = display.newText(“RESET”, 0, 0, “Helvetica”, 20 )
Reset:setReferencePoint(display.CenterCenterReferencePoint)
Reset.x = 50
Reset.y = centerY - 100
Reset:setTextColor (255, 255, 255 )
Reset.isVisible = true
TextGroup:insert(Reset)
Reset:addEventListener(“touch”, reset)

buildStage()

[/code]

I’m not sure if the collision filters are needed or not, I just wrote what I thought would work.

Hope this helps,

Nail [import]uid: 106779 topic_id: 34408 reply_id: 137058[/import]

I deleted my post after re-reading your question.

I think you want to implement a camera view that tracks your ball across the stage while possibly having the ball stay in the center of the screen. Your stage would actually be moving.

I’ve been using perspective.lua, by CalebP, which is found in the Community Code Exchange.

Link to perspective.lua

It’s a great module to implement a camera view.

Nail [import]uid: 106779 topic_id: 34408 reply_id: 136727[/import]

An additional note, if you’re using physics: whatever solution you use, if it involves moving display groups around, and you have your ball and various walls/boundaries/whatever in different groups, remember that you can’t shift those groups independently of each other or you’ll misalign the collision detection system and receive improper collisions.

Brent [import]uid: 200026 topic_id: 34408 reply_id: 136746[/import]

Thanks xnailbender and Brent,

I believe the perspective module is what I need but I am having some trouble getting it to work.
I don’t get any errors… but the ball still falls off the screen.
Here is my code.

[code]
local physics = require(“physics”);
physics.start();
local perspective = require(“perspective”)
local camera=perspective.createView()

local ballObject1 = display.newImageRect (“ballobject.png”,42,42)
ballObject1.x = 200
ballObject1.y = 200
physics.addBody( ballObject1, “dynamic”, { density=1.0, bounce=0.1, friction=0.15, radius=21} )

local function onTilt( event )
physics.setGravity( 10 * event.xGravity, -10 * event.yGravity )
end

Runtime:addEventListener( “accelerometer”, onTilt )

camera:add(ballObject1, 4, false)
camera:setBounds(0,480,0,480)
camera:track() [import]uid: 207525 topic_id: 34408 reply_id: 136788[/import]

Setting physics via a Runtime listener has got to be a poor choice performance-wise.

Have you tried just adding event Gravity to your ball ?

local function onTilt( event )  
 ballObject1.x = ballObject1.x + event.xGravity  
 -- use event.yGravity if you're in landscape mode  
end  

To keep the ball on screen, I’d place 4 static rectangles on the edges of your screen (or stage if it is a scrolling game. And then for scrolling, use the camera approach. [import]uid: 186251 topic_id: 34408 reply_id: 136806[/import]

That’s a nice suggestion Sam.

dpham, I didn’t run your code, but I think I see a problem. You haven’t told the camera to track your ball.

try to change this line and assign the ball as the object the camera tracks.

camera:add(ballObject1, 4, true)  

This should get you started.

FYI, getting the camera view to work can be tricky.

I’m not sure of your “stage” size, but I don’t think you’ve got your camera:setBounds properly set.

I think this is how it works…

By setting the x1 value to “0”, you are telling the camera to NOT track the ball for negative x values (off the left side of the screen).

By setting the x2 value to “480” your are tell the camera to STOP tracking the ball if it goes beyond the right edge of the screen. Same thing goes for the y1 and y2 values.
Experiment with the bounds values.

Maybe try this and look for a difference in behavior.

camera:setBounds(-1000, 1000, -1000 , 1000)  

Hope this helps,

Nail

[import]uid: 106779 topic_id: 34408 reply_id: 136815[/import]