imitate movement of paper.io2

Hi guys.

I would like to create a clone of the paper.io2 game but in 2D.

I would like to be able to move the main object as fluidly as in that game.

I tried to make touch events that change the angle of the object based on the movement of the finger and it works but it is not very fluid.

Does anyone have any tips?

For those who do not know the game here is a video( https://www.youtube.com/watch?v=CfuXiX0oCaQ )

There are a few different means of accomplishing this. Two of which would be either using linearVelocity with physics or changing the object’s coordinates in an enterFrame function.

In both cases, you’d want to set a constant velocity/speed for your object. With linearVelocity, you’d have to set gravity, linear damping and alike to 0 in order to keep the velocity constant. Then if the player wants to turn left or right, you’d adjust the linearVelocity accordingly. Using enterFrame would be similar and pretty straightforward as well, but you’d probably want to implement delta time here as well to maintain that stable movement.

How to actually accomplish all of that? Your best bet would be to utilise the unit circle, i.e. some basic trigonometry. I included the link just in case. You could simply state that the x and y movement speeds are cos and sin alpha multiplied by your desired movement speed. Then you control that alpha, i.e. the angle, via your controls.

@jake 

You want both the same input scheme and movement scheme as the sample game or just the movement and some arbitrary input scheme?

Sorry for the confusion, but there are inputs and there are responses.  What do you want to emulate?

Better yet, describe:

  • What you want the inputs to be.
  • What you want the response to those inputs to be.

PS - I’ve never played the game, but I’m looking for a copy to see what it does.  There seem to be many versions of this!!!

Maybe you mean just on iOS?  It would help if you specified the version you want to emulate.  :)   

Please don’t assume we’ll know what you mean.  Remember, Corona supports mobile, dekstop, and HTML5 so you could be targeting anything.

The input on this is pretty odd.

I downloaded it and repeatedly died trying to understand the input and response.  Ugh…  

The inputs and responses, as best I can tell are:

  • one touch
  • swipe left or down to rotate counter-clockwise
  • swipe right or up to rotate clock-wise

This however cannot be entirely correct.  When does up become right?  When does down become left?

I do not know and I didn’t have the patience to try to work it out.

My suggestion.  Skip the swipe input and use a two-touch touch input.  Touch left-side of screen to rotate counter clock-wise, touch right-side for clockwise.

Then get the movement working.

Later, you can switch input style.

I dug up an old example of mine and re-posted it here: 

https://github.com/roaminggamer/RG_FreeStuff/raw/master/AskEd/2018/11/SteeringCar.zip

This uses a two-touch input variation.  I think it may actually be a single touch that cares about what side of the screen you’re touching.

Still, it shows the ‘cube’ movement mechanics which is what your title implied you want.

@XeduR @Spyric

thanks for your tips actually what I’m doing at the moment is:

_set gravity to 0

_set a constant speed at runtime on the object(using physical functions)

_I use a touch event to calculate the angle of the user and change the direction of my object

this works but if I make small or fast movements it is not very fluid…

@roaminggamer

thank you, your advice is always very clear!

To start I refer to this game: https://play.google.com/store/apps/details?id=io.voodoo.paper2

as you can guess I tried it on android but I think it’s the same on iOS too.

I downloaded your project, it is interesting but not the fluidity that I expected.

To answer your other question:

_The input is the whole screen. The user must also be able to do various tractions without problems (like the sign of infinity)

_the output is the object that faithfully reflects everything that the user does with his finger

I hope I have made the idea better

Ok, I think I succeeded!

Using the  " joystick" library present in various templete offered by corona marketplace.

There is one thing I would like to do though and I can not:

When the stick reaches the death zone, I would like the entire joystick not to stay still but move to recover space.

looking for I found this video: https://www.youtube.com/watch?v=4nlMJxdjvtY (0:31 - 0:38)

I would like to imitate the dragging behavior of the blue joystick as seen in the video.

@roaminggamer I saw that you used the  joystick  library in some of your projects. What I ask can you do? I’m not succeeding…

Good to hear that you succeeded already. I got interested in this idea as well and I’ll whip up a quick project in the next 10 minutes to see if my enterFrame idea would even work. :stuck_out_tongue:

Here’s the sample code for what I had meant.

 

-- adjust pixelsPerFrame and deltaAngleStep to speed up the movement or direction change local pixelsPerFrame = 1 local deltaAngleStep = 0.15 local runtime = 0 local angle = 0 local buttonPressed = false local buttonActive local mathCos, mathSin = math.cos, math.sin local player = display.newCircle( 240, 160, 8 ) -- function for tracking which button is pressed and when local function changeAngle(event) if event.phase == "began" then buttonActive = event.target.id buttonPressed = true elseif event.phase == "ended" then buttonPressed = false end return true end -- movement angle buttons local buttonDown = display.newRect( 120, 160, 240, 320 ) buttonDown:setFillColor(1,0,0,0.1) buttonDown.id = "down" buttonDown:addEventListener("touch",changeAngle) local buttonUp = display.newRect( 360, 160, 240, 320 ) buttonUp:setFillColor(0,0,1,0.1) buttonUp.id = "up" buttonUp:addEventListener("touch",changeAngle) -- delta time function local function getDeltaTime() local temp = system.getTimer() --Get current game time in ms local dt = (temp-runtime) / (1000/60) --60fps or 30fps as base runtime = temp --Store game time return dt end local movement = function( event ) if buttonPressed == true then if buttonActive == "down" then angle = angle-deltaAngleStep else angle = angle+deltaAngleStep end end local dt = getDeltaTime() player:translate(mathCos(angle)\*pixelsPerFrame\*dt,-mathSin(angle)\*pixelsPerFrame\*dt) end Runtime:addEventListener( "enterFrame", movement )

The enterFrame function moves the player constantly and holding either the red or blue button/area down will change the angle of the movement.

Actually, I have my own joystick library in SSK:

Having said that, my joystick core-library does NOT support dragging beyond the edge, at least not out of the box.

PS - You used the term ‘death zone’.  There isn’t such a thing for (physical) joysticks.  There is however a ‘dead zone’. 

That is in the center and is an area where old mechanical joysticks did not register movement.

Just wanted you to know so you don’t use the wrong terms in the future.

I think  you are actually saying, you want the joystick to be dragged along once the stick reaches and then exceeds the outer edge of the (virtual) joystick.

Tried the game for a few minutes - this looks pretty simple? Does not require a virtual joystick or anything like that.

All it does is tracking your touch movement as a desired direction vector (maybe by just adding the dx/dy of the touch and clamping to a maximum) and adjust the direction of your vehicle into that direction. The lenght of your touch tracking vector defines how big it’s impact on your vehicle. The touch tracking vector also shrinks each frame so if you don’t keep moving, the change of direction slows down.

The speed of the vehicle seems to be constant, so in the end it’s probably as simple as

vecVelocityVehicle = constantVehicleSpeed * normalize( vecVelocityVehicle + vecTouchTracked)

With a bit of tweaking in the max values the touch tracking vector is clamped to (if at all) and the way it decreases over time (I guess it’s percentage per Frame instead of a constant value as this helps to filter extreme movements a lot).

Here’s a sample implementation which probably is pretty much all there is to it … not perfectly tweaked as it’s just a quick hack, but it shows the basic way of how it’s done. Just paste the code into main.lua of a new blank project.

Also, the rotation is probably wrong, but with a rect it doesn’t show :slight_smile:

[lua]


– main.lua


local vehicle = display.newRect( 0, 0, 10, 10 )

local speed = 100

local dt = 1/60

local touch = { x = 0, y = 0 }

vehicle.vel = { x = speed, y = 0 }

function update( event )

    local vel = vehicle.vel

    vehicle.x = vehicle.x + vel.x * dt

    vehicle.y = vehicle.y + vel.y * dt

    vel.x = vel.x + touch.x

    vel.y = vel.y + touch.y

    local velLen = math.sqrt( vel.x*vel.x + vel.y*vel.y )

    vel.x = vel.x / velLen * speed

    vel.y = vel.y / velLen * speed

    touch.x = touch.x * 0.3

    touch.y = touch.y * 0.3

    local RAD2DEG = 180 / math.pi

    local angle = (math.atan2( vel.y, vel.x ) * RAD2DEG)

    vehicle.rotation = angle

end

function handleTouch( event )

    local phase = event.phase

    if phase == “began” then

    else

        touch.x = touch.x + (event.x - touch.lastX)

        touch.y = touch.y + (event.y - touch.lastY)

    end

    touch.lastX = event.x

    touch.lastY = event.y

end

Runtime:addEventListener( “touch”, handleTouch )

Runtime:addEventListener( “enterFrame”, update )

[/lua]

@ XeduR @Spyric

I’m glad you’ve been interested in trying! However, the result is not accurate what I’m looking for.

@ roaminggamer

You clarified the point, my interest was in moving the joistik once the maximum is reached.

I’m sorry it has not been integrated yet, I think it would be useful. Is it very complicated to do?

@ Michael Flad

If the one that came closest to the first shot !! Actually, I think using your code would not be bad. It has only minor problems when (for example, go ahead and immediately after). Do you have any precautions that could make it perfect? I have some math problems in some situations …

Edit: For the rotation is not a problem, I’ve already adjusted it. I’m really interested in the fluid movement

Edit2:bad traslate

Yeah, by the time you posted those joysticks and everything, I knew that it wasn’t what was asked anymore. :smiley:

Non sono sicuro di quanto sarebbe difficile integrare una funzione di “trascinamento”. Probabilmente non troppo difficile.

I’m not sure how hard it would be to integrate a ‘dragging’ feature.  Probably not too hard.

I investigated and this is a change that I can’t afford the time to make right now.

Will take about 30 minutes to change my code and 30 more to test for negative-side-effects in the various standard uses (in SSK). So, too long for now.

You’d probably be best served coding up your own solution for the input code this time around.

I’m not sure what you mean with regards to going ahead and after … maybe a translation problem?

@roaminggamer
I understand… thanks anyway for your availability!

@Michael Flad
I’m sorry. As I said, I got confused with the translation. The crucial problem is: I can not execute a symbol (like 8) in a fluid way

Ah I see … well it’s all about the tweaking - also they may use other formulas to apply the changes (like interpolating the rotation instead of adding vectors etc.) - it’s only meant as a simple starting point for the general idea.

Here’s a slightly tweaked version, also added a small startup delay to give it a try on a device and a simple trail (obviously for a real implementation you’d have to use meshes).

I can easily move in a 8 or similar symbols with this version, but of course it’s still not 100% identical - again, just meant to give you a starting point.

[lua]

local vehicle = display.newRect( display.contentWidth/2, display.contentHeight/2, 10, 10 )

local speed = 120

local dt = 1/60

local appear = transition.from( vehicle, { delay = 1000, time = 800, transition = easing.outElastic,

    alpha = 0, xScale = 0.01, yScale = 0.01,

    onComplete = function() Runtime:addEventListener( “enterFrame”, update) end })

local touch = { x = 0, y = 0 }

vehicle.vel = { x = speed, y = 0 }

local FRAMES_PER_TRAIL = 4

local trail = { nextTrail = FRAMES_PER_TRAIL }

print( trail.nextTrail )

function update( event )

    local vel = vehicle.vel

    vehicle.x = vehicle.x + vel.x * dt

    vehicle.y = vehicle.y + vel.y * dt

    vel.x = vel.x + touch.x

    vel.y = vel.y + touch.y

    local velLen = math.sqrt( vel.x*vel.x + vel.y*vel.y )

    vel.x = vel.x / velLen * speed

    vel.y = vel.y / velLen * speed

    touch.x = touch.x * 0.5

    touch.y = touch.y * 0.5

    local RAD2DEG = 180 / math.pi

    local angle = (math.atan2( vel.y, vel.x ) * RAD2DEG)

    vehicle.rotation = angle

    trail.nextTrail = trail.nextTrail - 1

    if trail.nextTrail <= 0 then

        trail.nextTrail = FRAMES_PER_TRAIL

        local r = display.newRect( vehicle.x, vehicle.y, 10, 10 )

        r.rotation = vehicle.rotation

    end

end

function handleTouch( event )

    local phase = event.phase

    if phase == “began” then

    else

        touch.x = touch.x + (event.x - touch.lastX) * 3

        touch.y = touch.y + (event.y - touch.lastY) * 3

    end

    touch.lastX = event.x

    touch.lastY = event.y

end

Runtime:addEventListener( “touch”, handleTouch )

[/lua]

Well!

Now that is better is almost perfect! F

or the meash no problem I know how to do. I was more interested in fluidity.

Thank you so much!