Rotating Plane with Buttons *SOLVED*

I understand I recently made a post similar to this, wherein I was trying to rotate the background instead of the plane. However, I changed my code drastically because I realized I was making the code really awkward by rotating/moving the background instead of doing the same thing to the plane and having the screen follow it.

What I want is to be able to rotate the plane using my left and right buttons and have the screen kinda rotate with it. I have the screen following the plane in x and y coordinates, but I need it to rotate with it as well. Here’s my main code:

[code]
local physics = require(“physics”)
physics.start()
physics.setGravity( 0, 0 )

display.setStatusBar(display.HiddenStatusBar)

local physicsData = (require “shapedefs”).physicsData(1.0) – Enables special physics shapes for objects.

system.activate( “multitouch” )
local airSpeedPlayer = 5 – This determines the speed at which the player moves.

local turnSpeedPlayer = 0.001 – This determines the speed at which the player turns.

local game = display.newGroup( ) – This group is used to ‘scroll’ the screen.
game.x, game.y = 0, 0

local leftTouched = true – These are booleans used to determine whether
local rightTouched = false – one of the buttons is being touched or not.

local playerIsAlive = true – This determines if the player is ‘alive’ or not.

local bkg = display.newImage(“bkg.png”, true)
bkg.x = display.contentWidth / 2
bkg.y = display.contentHeight - (625 / 2) – The exact numbers here are optional; they ensure that the background is positioned so that the bottom of the image is touching the bottom of the screen.
bkg.alpha = 0.5 – Not strictly necessary.
game:insert( bkg )

local plane = display.newImage(“plane.png”)
plane.x, plane.y = display.contentWidth / 2, display.contentHeight / 2
physics.addBody ( plane, physicsData:get(“plane”) )
plane.isSleepingAllowed = false – Keeps the plane from falling asleep.
game:insert( plane )
plane:setLinearVelocity( 0, -airSpeedPlayer ) – Gets the plane moving.

local rightArrow = display.newImage(“rightArrow.png”) – This arrow is used to turn the player left.
rightArrow.x = display.contentWidth - 38.5
rightArrow.y = display.contentHeight - 38

local leftArrow = display.newImage(“leftArrow.png”) – This arrow is used to turn the player right.
leftArrow.x = 38.5
leftArrow.y = rightArrow.y

local function moveCamera() – This function is used to ‘scroll’ the screen.
if playerIsAlive == true then – By determining if the player is ‘alive’ or not, a fatal error can be prevented when/if the player’s plane is removed.
game.x = -(plane.x - 160)
game.y = -(plane.y - 240)
end
end

Runtime:addEventListener ( “enterFrame”, moveCamera )

physics.setDrawMode( “normal” )[/code]
Thank you in advance. [import]uid: 82408 topic_id: 27992 reply_id: 327992[/import]

The key part of all this is keeping the reference point of the group ‘game’ on the center of the screen (i.e. where the plane will be). I’ve tried various methods of doing this, but none of them seem to be working. Part of the problem is getting the math right. Currently, I’m trying the following:

[code]local function setGameReference()
game.referenceX = -(game.x - display.contentCenterX)
game.referenceY = -(game.y - display.contentCenterY)
end

Runtime:addEventListener( “enterFrame”, setGameReference )

local function leftRotate()
if leftTouched == true and rightTouched == false then
plane:rotate( -turnSpeedPlayer )
game.rotation = -(plane.rotation)
elseif leftTouched == false then return false
end
end

local function leftTouch( event )
if event.phase == “begun” then
leftTouched = true
print ( leftTouched )
elseif event.phase == “ended” then
leftTouched = false
end
end

timer.performWithDelay ( 250, leftRotate, 0 )
leftArrow:addEventListener ( “touch”, leftTouch )[/code]
However, the touch listener on the object ‘leftArrow’ is not responding at all. I’m not getting any error signals in Terminal, so it’s just that the function ‘leftTouch’ isn’t getting called. Why is this? [import]uid: 82408 topic_id: 27992 reply_id: 113692[/import]

The reason why your leftTouch probably isn’t responding is because of a mistype

if event.phase == "begun" then  

It’s supposed to be

if event.phase == "began" then  

[import]uid: 77199 topic_id: 27992 reply_id: 113745[/import]

Thanks. Now it’s working. However, the group isn’t quite rotating the way I need it to. It seems that the reference point for the group is at the top-left corner of the screen, and when it rotates, the plane moves with it. Granted, after I stop rotating, the plane slowly moves back to the center of the screen, but that’s not good enough; I need it to stay in the center of the screen even as the group rotates. I have a feeling that by fixing the reference point, the problem should stop, but I can’t be totally sure.

Now, I need the reference point for the group ‘game’ to be continually updated to become the center of the screen, obviously. The question is, how would I do that? I know the whole Runtime:addEventListener(“enterFrame”, listener) thing, but what is the math I would use to calculate the distance between the local origin of ‘game’ and the center of the screen and then act upon it? [import]uid: 82408 topic_id: 27992 reply_id: 113961[/import]

I need a few more details from you. This game plays in portrait, right? How big is your background image exactly?

What you are trying to achieve is, you have your plane flying upwards by default and when you click left arrow he starts rotating to the left, likewise with right arrow. You also want your bg to rotate accordingly with your plane moving while keeping the plane centered on the screen? That’s all? [import]uid: 77199 topic_id: 27992 reply_id: 114008[/import]

Yes, it is in portrait. Also, the background image is 873x625. However, keep in mind that I plan for there to be multiple ‘levels’ if you will, that borrow the same player movement code. In each level, the background images would have different sizes, so the rotation code would have to depend on variables, not off of exact numbers that I have to finetune each time I create the code for a new level.

Now, it’s not just the background that’s rotating. It’s the group called ‘game’, which includes the background, the player, and various other objects that I have yet to add to the code. Basically, I need the group to rotate at the same speed as the player, but in the opposite direction (i.e. if the player rotates clockwise, the group rotates counter-clockwise). It also needs to always rotate around the center of the screen, which is where the plane will be. [import]uid: 82408 topic_id: 27992 reply_id: 114139[/import]

Going to try and explain as best as I can the problems you are having. The solution to your problem is pretty easy actually.

Let me answer your previous question:

However, the group isn't quite rotating the way I need it to. It seems that the reference point for the group is at the top-left corner of the screen, and when it rotates, the plane moves with it. Granted, after I stop rotating, the plane slowly moves back to the center of the screen, but that's not good enough; I need it to stay in the center of the screen even as the group rotates. I have a feeling that by fixing the reference point, the problem should stop, but I can't be totally sure.

The reason why the rotating is off is because you have the plane added to the game group. Therefor you are rotating the plane once clockwise, then also rotating it with the entire group ‘game’ counter clockwise. I also think you are setting the reference point wrong. I’m not expert in reference points since I never really use them, but I looked up the API and found a solution that I believe fits your needs and doesn’t require a Runtime to use up more resources. I’m not 100% if this is what you want but you’ll have to look at it and let me know. Let me start explaining

First of all, you will need an entirely new group. Let’s call it camera.

local camera = display.newGroup()  
camera.x, camera.y = 0, 0  

You first have to remove your plane from the game group, then add the plane to your camera group and also add the game group to the camera group. Then in your moveCamera function you will change game.x and game.y to camera.x and camera.y. This alone will keep your plane centered all the time even during rotation without it ever leaving the center.

Instead of your setGameReference function, try using this instead:

game:setReferencePoint(display.CenterReferencePoint)  

You might have to recall that code every time you add something to the game group, not sure about that though. But it should still use less resources than a Runtime listener.

Hope this makes sense to you, if not, please let me know and I will try to explain it differently. Your code is working, all you really have to do it:

  1. Create a new display.newGroup called camera.
  2. Remove your plane from the game group, add the plane to the camera group and then add the game group to the camera group.
  3. Change the setGameFunction to the code above and it should work exactly like you want it.

About the rotation code and needing variables, I don’t think you do anymore. Unless I’m misunderstanding something. Please try the code above and let me know if it works the way you’d like it too, otherwise please let me know what’s still not working properly. Best of luck
[import]uid: 77199 topic_id: 27992 reply_id: 114145[/import]

I altered your code a little just so I could test it out. Wasn’t sure if I should post it or not since it’s kinda messy. But I’ll post it just so you have an example as well:

[code]
local physics = require(“physics”)
physics.start()
physics.setGravity( 0, 0 )

display.setStatusBar(display.HiddenStatusBar)

local airSpeedPlayer = 5 – This determines the speed at which the player moves.

local turnSpeedPlayer = 1 – This determines the speed at which the player turns.

local game = display.newGroup( ) – This group is used to ‘scroll’ the screen.
game.x, game.y = 0, 0

local camera = display.newGroup()
camera.x, camera.y = 0, 0

local leftTouched = true – These are booleans used to determine whether
local rightTouched = false – one of the buttons is being touched or not.

local playerIsAlive = true – This determines if the player is ‘alive’ or not.

local bkg = display.newRect( 50, 50, 873, 625)
bkg.x = display.contentWidth / 2
bkg.y = display.contentHeight - (625 / 2) – The exact numbers here are optional; they ensure that the background is positioned so that the bottom of the image is touching the bottom of the screen.
bkg.alpha = 0.5 – Not strictly necessary.
game:insert( bkg )

local plane = display.newRect( 160, 240, 40, 40)
plane.x, plane.y = display.contentWidth / 2, display.contentHeight / 2
physics.addBody ( plane, dynamic )
plane.isSleepingAllowed = false – Keeps the plane from falling asleep.
camera:insert(plane)
– game:insert( plane )
plane:setLinearVelocity( 0, -airSpeedPlayer ) – Gets the plane moving.

local rightArrow = display.newCircle( 10, 10, 30) – This arrow is used to turn the player left.
rightArrow.x = display.contentWidth - 38.5
rightArrow.y = display.contentHeight - 38

local leftArrow = display.newCircle( 10, 10, 30) – This arrow is used to turn the player right.
leftArrow.x = 38.5
leftArrow.y = rightArrow.y

camera:insert(game)

local function moveCamera() – This function is used to ‘scroll’ the screen.
if playerIsAlive == true then – By determining if the player is ‘alive’ or not, a fatal error can be prevented when/if the player’s plane is removed.
camera.x = -(plane.x - 160)
camera.y = -(plane.y - 240)
end
end

Runtime:addEventListener ( “enterFrame”, moveCamera )

physics.setDrawMode( “normal” )

– local function setGameReference()
game:setReferencePoint(display.CenterReferencePoint)
– game.referenceX = -(game.x - display.contentCenterX)
– game.referenceY = -(game.y - display.contentCenterY)
– end

– Runtime:addEventListener( “enterFrame”, setGameReference )

local function leftRotate()

plane:rotate( -turnSpeedPlayer )
game.rotation = -(plane.rotation)

end

local function leftTouch( event )
if event.phase == “began” then
leftTouched = true
print ( leftTouched )
elseif event.phase == “ended” then
leftTouched = false
end
end

– timer.performWithDelay ( 250, leftRotate, 0 )
leftArrow:addEventListener ( “touch”, leftRotate )
[/code] [import]uid: 77199 topic_id: 27992 reply_id: 114218[/import]

Thanks! It’s finally working nicely. Your method did seem a little odd at first, partly because I thought game:setReferencePoint(display.CenterReferencePoint) wouldn’t work the way I needed it to. I guess I was wrong. Merci beaucoup!

Cheers,
Perseus [import]uid: 82408 topic_id: 27992 reply_id: 114961[/import]