Player movement with Touch

This is following up on a discussion started with spenggong in the ‘tutorial request’ thread.

#1: Math and coding while half asleep are apparently poor choices on my part.

#2: Updated code that I actually tested this time :slight_smile:


local stopP = function()
p:setLinearVelocity(0,0)
end

local moveP = function()
–Prevents timer from stopping movement prematurely if there are multiple touches before player stops
if t then timer.cancel(t) end

–sets maximum velocity
vmax = 100

–calculates distance to travel in components and total distance squared
dx = eventX-p.x
dy = eventY-p.y
ds = (dx*dx + dy*dy)

–finds scaling so that total velocity =vmax
scalefactor= (vmax^2/ds )^0.5

vely=dy * scalefactor
velx=dx * scalefactor

–amount of time it takes to travel to point of touch at vmax
traveltime = 1000 * (ds^0.5)/vmax

p:setLinearVelocity(velx,vely)

–stops movement after reaching touch point
t= timer.performWithDelay(traveltime,stopP)

end


Movement will still occur once running into a wall but not through the wall in this case. What happens depends on bounce and friction values. I added an event listener for collisions in my version and when one occurs I set the velocities to zero but what you do there depends on what you want the game to do. Hope this helps! [import]uid: 39394 topic_id: 10000 reply_id: 310000[/import]

@slojoe1559 I find myself making happy accidents when designing in Photoshop and falling asleep at the same time. When it comes to coding there’s no mercy :slight_smile: Thanks again. I will try the new implementation when in a few minutes.
[import]uid: 53149 topic_id: 10000 reply_id: 36498[/import]

@slojoe1559 One more question… this is something I struggle to find on the forums.

  1. I have a level map that is 2048 x 2048 ( the max size I use)

  2. I have my player spawning in the center of the map and center of the iOS screen

  3. How move the map when the player say gets with 80px (±) of either side of the map. For example, my player moves to the upper right… I want the map to move/scroll as to not have my player stuck in the upper right corner.

I guess I want the camera to have an offset. I don’t know how to phrase it. I hope you get the idea. If not I will try to be a little clearer

Thanks [import]uid: 53149 topic_id: 10000 reply_id: 36609[/import]

Just to make sure I understand what you want to do…you’re looking to have the map scroll when the player is moving close to the edge of the screen, but not scroll at all when far enough away from the edge?

Being touch to move, I would recommend having a larger pixel amount for the buffer than 80 as that would make it difficult to move far past the original visible map. An alternative would be to always have the camera focused on the player. I’ll show examples of both below:
Something like this should work for your idea.

local function moveCamera ()

local buffer=80

if (p.x map:move(-5,0)
elseif (p.x>(display.contentWidth-buffer)) then
map:move(5,0)
end

if (p.y map:move(0,5)
elseif (p.y>(display.contentHeight-buffer)) then
map:move(0,-5)
end

end

-----------------------------------------------------


To keep in the center of the screen:
--------------------------------------

local function moveCamera()

map:setPosition(p.x, p.y)

end
--------------------------------------
This is the method I prefer for it’s simplicity, though I can not say whether one option would be better performance-wise. [import]uid: 39394 topic_id: 10000 reply_id: 36619[/import]

@slojoe1559 That is exactly what I was referring to. Thanks!

[import]uid: 53149 topic_id: 10000 reply_id: 36651[/import]

@slojoe1559 I am not sure what I’m missing, but neither option worked. I got the following errors:

local function moveCamera ()

local buffer=80

if (p.x(display.contentWidth-buffer)) then
map:move(5,0)
end

if (p.y(display.contentHeight-buffer)) then
map:move(0,-5)
end

end

ERROR:

/main.lua:42: attempt to call field ‘x’ (a number value)


local function moveCamera()

map:setPosition(p.x, p.y)

end

ERROR:

/main.lua:52: attempt to call method ‘setPosition’ (a nil value)
I tried calling the function moveCamera on every frame. Then I tried calling it on “touch”. I knew they would both trigger an error, but just so you know what I tried.

Thanks for your help
[import]uid: 53149 topic_id: 10000 reply_id: 36872[/import]

@spenggong - First, replace ‘map’ with whatever you call your map (I believe it was ‘levelMap’ from earlier in the discussion). Second, the first bit of code I provided should look more like what I include below (switching player and map for what you call them). Hope this helps!

local function moveCamera()

local buffer=120
local speed=2

if (player.x map:move(-speed,0)
elseif (player.x>(display.contentWidth-buffer)) then
map:move(speed,0)
end

if (player.y map:move(0,speed)
elseif (player.y>(display.contentHeight-buffer)) then
map:move(0,-speed)
end
end

[import]uid: 39394 topic_id: 10000 reply_id: 36888[/import]

@slojoe1559- I tried what you just posted. Same error. Here’s how I have it. Maybe you can see the issue:
local physics = require(“physics”)

physics.start()
–physics.setScale( 50 )
physics.setGravity( 0,0)
physics.setDrawMode(“hybrid”)
local eventX
local eventY
local levelMap = display.newGroup ()
local map = display.newImage(“img/test.jpg”, true)
map.x = display.contentWidth / 2
map.y = display.contentHeight - 80
levelMap:insert(map)

– p = player
local p = display.newRect(150, 200, 15, 15) – Drawing a rect just for testing
p:setFillColor(20, 20, 25)
physics.addBody(p, {bounce = 0.5, friction = 0.5, density = 2.0, radius = 10 })
p.name = “p”

local function moveCamera()
local buffer = 120
local speed = 2

if(p.x(display.contentWidth - buffer )) then
levelMap:move(0, -speed)
end

if(p.y(display.contentHeight - buffer )) then
levelMap:move(0, -speed)
end
end
local stopP = function ()

p:setLinearVelocity(0,0)
end

local moveP = function ()

if t then timer.cancel(t) end

– PLayer speed
vmax = 50

dx = eventX-p.x
dy = eventY-p.y
ds = (dx*dx + dy*dy)

scalefactor = (vmax^2/ds)^0.5

vely = dy * scalefactor
velx = dx * scalefactor

traveltime = 1000 * (ds^0.5) / vmax

p:setLinearVelocity(velx, vely)

t = timer.performWithDelay(traveltime, stopP)

end
local l = function ( event )
if(event.phase == “began”) then

eventX = event.x
eventY = event.y
moveCamera ()
moveP ()
end
end

map:addEventListener(“touch”, l)
[import]uid: 53149 topic_id: 10000 reply_id: 36889[/import]

It’s hard to read the code when it’s not got < code > tag around it but this line confuses me:

  
if (player.x(display.contentWidth-buffer)) then  
  

You seem to be trying to call a variable like it’s a method. I assume you mean something like this:

[code]

if player.x > display.contentWidth-buffer then

[/code] [import]uid: 5833 topic_id: 10000 reply_id: 36947[/import]

@GrahamRanson - I tried what you suggested:

if player.x > display.contentWidth-buffer then

It got rid of the error, but I notice you both are using a method called “move”. I don’t have that defined anywhere in the sample code I am working from. Is this something built in like “transition.to”? Here the error I am getting now:
sandbox_tribal/main.lua:58: attempt to call method ‘move’ (a nil value)

Here’s the code setup:

[code]
local function moveCamera ()

local buffer = 80
local speed = 2

if(p.x > display.contentWidth - buffer) then
map:move(speed,0)
end

if(p.y > display.contentHeight - buffer) then
map:move(0, - speed)
end
end

Runtime:addEventListener(“enterFrame”, moveCamera)
I feel like I am close and thank you guys for all the help. If you can just help me

  1. Move th eplayer based on touch (WORKS) :slight_smile:

  2. Keep character centered in map when moves/ Have camera follow character around 2048x2048 map

  3. Have map move/adjust to keep character centered when player gets to the edge of the iphone screen… Pretty much I think two would handle that. Thanks…
    Here’s all the code I have so far:

[code]

local physics = require(“physics”)
–local lime = require(“lime”)

physics.start()
physics.setScale( 50 )
physics.setGravity( 0,0)
physics.setDrawMode(“hybrid”)
local eventX
local eventY

local levelMap = display.newGroup ()

–local map = display.newRect(0,0,1024,1024)
– map:setFillColor(35, 230, 100)
– levelMap:insert(map)

local map = display.newImage(“img/test.jpg”, true)
map.x = display.contentWidth / 2
map.y = display.contentHeight - 80
levelMap:insert(map)

local p = display.newRect(150, 200, 15, 15)
p:setFillColor(20, 20, 25)
physics.addBody(p, {bounce = 0.5, friction = 0.5, density = 2.0, radius = 10 })
p.name = “p”

–local function moveCamera ()

– if(p.x > 80 and p.x < 1024) then
– levelMap.x = -p.x + 20
– end

– if(p.y > 80 and p.y < 1024) then
– levelMap.y = -p.y + 20
– end
–end

–Runtime:addEventListener(“enterFrame”, moveCamera)

local function moveCamera ()

local buffer = 80
local speed = 2

if(p.x > display.contentWidth - buffer) then
map:move(speed,0)
end

if(p.y > display.contentHeight - buffer) then
map:move(0, - speed)
end
end

Runtime:addEventListener(“enterFrame”, moveCamera)

local stopP = function ()

p:setLinearVelocity(0,0)
end

local moveP = function ()

if t then timer.cancel(t) end

– PLayer speed
vmax = 50

dx = eventX-p.x
dy = eventY-p.y
ds = (dx*dx + dy*dy)

scalefactor = (vmax^2/ds)^0.5

vely = dy * scalefactor
velx = dx * scalefactor

traveltime = 1000 * (ds^0.5) / vmax

p:setLinearVelocity(velx, vely)

t = timer.performWithDelay(traveltime, stopP)

end
local l = function ( event )
if(event.phase == “began”) then

eventX = event.x
eventY = event.y
moveP ()
end
end

map:addEventListener(“touch”, l)

–local function onCollision(self, event)
– if(self.name == “wall” and event.other.name == “p”) then
– print(“Player has reached a wall”)
– t = timer.performWithDelay(traveltime, stopP)
– end

–end

–wall.collision = onCollision
–wall:addEventListener(“collision”, wall)

[code]
[import]uid: 53149 topic_id: 10000 reply_id: 36980[/import]

I am apparently having problems posting on here as my last two posts clarifying my errors have not shown up. Assuming this shows up I will will repost what I tried to before in a minute. [import]uid: 39394 topic_id: 10000 reply_id: 37013[/import]

@slojoe1559 - I was trying to find a way to post an image ealier and could not. The forum needs some minor features added. Other than that, I can see your post. Please Please re-post your solution. I am going nuts. [import]uid: 53149 topic_id: 10000 reply_id: 37019[/import]

The move method is from lime. For moving around a background image as you are attempting above, you could probably use something like:

map.x=map.x-speed  

in place of

map:move(-speed,0)  

Below are the two pieces of code I attempted to show before but using < code > < /code >. Thank you Graham for pointing that out.

Note that after testing this, it is far from perfect, but does move the map.

local function moveCamera() local buffer=120 local speed=2 if (player.x<buffer then> map:move(-speed,0)<br> elseif (player.x&gt;(display.contentWidth-buffer)) then<br> map:move(speed,0)<br> end<br><br> if (player.y<buffer then> map:move(0,speed)<br> elseif (player.y&gt;(display.contentHeight-buffer)) then<br> map:move(0,-speed)<br> end<br>end<br>
The simpler method is shown below (again I believe this requires lime to work). I do run into issues near the right edge of the map with the map jumping ~50 pixels just after the right edge coming into view/leaving view.
<br>local function moveCamera()<br> map:setPosition(player.x,player.y)<br>end<br> [import]uid: 39394 topic_id: 10000 reply_id: 37020[/import]

@slojoe1559 - So no more errors. Thanks guys:

How do I get the map to stop moving when the player stops. Right now the map keeps going none stop. I add:

[code]
Runtime:removeEventListener(“enterFrame”, moveCamera)

[code]
local moveP = function ()

if t then timer.cancel(t) end

– PLayer speed
vmax = 50

dx = eventX-p.x
dy = eventY-p.y
ds = (dx*dx + dy*dy)

scalefactor = (vmax^2/ds)^0.5

vely = dy * scalefactor
velx = dx * scalefactor

traveltime = 1000 * (ds^0.5) / vmax

p:setLinearVelocity(velx, vely)

t = timer.performWithDelay(traveltime, stopP)
Runtime:removeEventListener(“enterFrame”, moveCamera)

end
That stops the map when the player stops, but after clicking again the map no longer moves. I apologize for the never ending questions. I just don’t see anyone trying to do a point click/ touch RPG game.

The movement is my biggest challenge [import]uid: 53149 topic_id: 10000 reply_id: 37083[/import]

I was looking at the movement style in Dragon Quest and that’s something similar to what I am trying to do. I bought lime, but not planning on using it for this as I am not sure how well it works with the Director class and I’d rather stick to something I can accomplish for my hobby projects. This is more of a learning experience and a hobby so any help with the movements would be great. I can do this relatively easy in Unity 3D, but Unity 3D is overkill for a 2d game. Best used for 3D worlds.

If you ever need help with graphics let me know. Not that I am saying you guys don’t design :slight_smile: Just trying to be helpful any way I can since you all helping me figure this out.

  1. Character movement is good… thanks to @slojoe1559
  2. Got map movement thanks to slojo1559 again

PROBLEM: When I touch a point on the screen… my char travels as expected to that point. If it’s near the edge… the map adjusts keeping the player in view, but the map keeps moving even after the player stops. How do I fix that?

I need some logic i’m guessing that detects when player movement stops. I am using a :

[code]
Runtime:addEventListener(“enterFrame” moveCamera)

To continuously listen for player.x and player.y movement

[code]
I then tried using Runtime:removeEventListener(“enterFrame”, moveCamera)

That stops the map and never moves it again.

THANKS ALL [import]uid: 53149 topic_id: 10000 reply_id: 37195[/import]

I would suggest adding a line to your stopP() function to stop the map movement as well.

local function stopP()  
 p:setLinearVelocity(0, 0)  
 map:move(0,0)  
end  

I might also suggest something to stop movement when the player walks into an object (so that both player and map stop in this example):

local function onCollision(self, event)  
 if event.phase=="began" then  
 if t then timer.cancel(t) end  
 stopP()  
 end  
end  
  
p.collision = onCollision  
p:addEventListener("collision",p)  

By the way, when posting code snippets, you can use < /code > to end the code segment on the forums here. Good luck :slight_smile: [import]uid: 39394 topic_id: 10000 reply_id: 37198[/import]

@slojoe1559 - Thank you! Thank you! It’s working technically, I have to play with the math value a bit to get it smoother, but until something better comes. I can work with this. If you come up with anything better, if you don;t mind adding it to the Code Exchange and ping. I truly appreciate your help and time on this. I am on my way to learn this thing and maybe I too can contribute. I am coming from a design background. Got tired of my works being static. Here I am. Maybe an RPG type game should not be my first attempt, but I hate those simple games with no stories.

I love Dragon Quest, FF I

Thanks [import]uid: 53149 topic_id: 10000 reply_id: 37251[/import]

This topic was incredibly useful for people that are making similar games, such as myself. I vote for a full tutorial on map scrolling and player control. It seems every second question in the forums is about this topic

Thanks slojoe1559 & spenggong

Big Ups [import]uid: 26289 topic_id: 10000 reply_id: 42030[/import]

There are currently 2 tutorials on controlling the camera - http://justaddli.me/tutorial.php?t=0&id=13 and http://justaddli.me/tutorial.php?t=0&id=20 - however a tutorial on different types of player movement could certainly be useful. [import]uid: 5833 topic_id: 10000 reply_id: 42065[/import]

Sorry Graham didn’t realise this topic was located in the Lime subforum. Cheers tho [import]uid: 26289 topic_id: 10000 reply_id: 42220[/import]