Corona SDK: Moving a player Up and Down - lua

I have a player who is navigating in space. Since it is space, there is not gravity therefore no parabolic trajectory. The player is just going in a horizontal line from left to right. The player is not actually moving, but the background is, so it looks like he is. The x value is fixed.
I have 2 buttons that help the player avoid obstacles like asteroids. One button gives the player upward force, the other one downward force. The following are the functions called when those buttons are pressed.
function moveUp( event )
if event.phase == "ended" then
player:applyForce(0, 8, player.x, player.y)
player:setSequence("jump")
jumpChannel = audio.play(jumpSound)
end
return true
end
function moveDown( event )
if event.phase == "ended" then
player:applyForce(0, -8, player.x, player.y)
player:setSequence("jump")
jumpChannel = audio.play(jumpSound)
end
return true
end
The problem with this implementation is that whenever a force is applied the player keeps going in that direction. Then you have to apply force in the opposite direction and he will keep going in that direction forever. That is not what I want. What I want is :
when UP is pressed, player goes up for certain value (say 50 px) in Y. Then the player keeps going in the horizontal direction from left to right in the new altitude.
When DOWN is pressed, player goes down certain value. Then the player keeps going in the horizontal direction from left to right in the new altitude.
What is the best way to accomplish this? Can I do this using the applyForce function or is there another method? Thanks in advance for your time!

You have to remember that F=ma: if force applied is 0, a is 0, which means velocity does not change. You have two choices:
apply an opposite force that will decrease the speed, and stop when speed is 0. Every Body has myBody.linearDamping factor which you could set to non-zero. If that doesn't work, you can apply your own damping: you make it proportional to Body velocity, so you need an enterFrame event handler that updates the force based on current velocity:
function enterFrame(e)
local v = player:getLinearVelocity()
player:applyForce(- a * v)
end
Here the "a" is damping, some arbitrary number (0 is what you have now; the larger it is, the faster the player will return to 0 velocity). I haven't checked whether the applyForce() is additive (adds to existing forces) or absolute (replaces existing). But you get the idea.
directly move the player:
function moveUp( event )
if event.phase == "ended" then
player:setLinearVelocity(0, 8) -- pixels/sec
You will still need an enterFrame handler to monitor position and setLinearVelocity(0,0) when desired position reached.
You will get smoother, more "realistic" motion with option 1.

Related

Roblox Lua Humanoid:Move

Pardon the noob question, I am new to Roblox LUA.
I am trying to make the humanoid move forwards and backwards, (as when an officer, guards a perimeter by moving to and fro) but there may be something wrong with this script, because it only moves forwards.
local toggle = true
local RunService = game:GetService("RunService")
local humanoid = game.Players.LocalPlayer.Character:WaitForChild("Humanoid")
RunService:BindToRenderStep("Move", Enum.RenderPriority.Character.Value + 1, function()
while toggle do
humanoid:Move(Vector3.new(0, 0, -1), true)
wait(1)
humanoid:Move(Vector3.new(0, 0, 1), true)
wait(1)
end
end)
And then when I toggle = false, it does not stop.
I can't use keypress as it defeats the purpose of what I intend to do.
Thank you for any assistance.
The way this code is structured does not make much sense. You're creating a loop inside a function that is triggered every frame. Every single frame, you create a new loop... After just 10 seconds you might have 300 loops trying to move the humanoid at the same time.
Because the loops constantly overwrite each other, the last one to run takes precedence... Which is likely why it's only towards one direction.
I presume you want to make the character move towards (0,0,-1) for a second, then towards (0,0,1) for another second and then, if toggle is enabled, run again.
What you should be doing instead is not creating a loop inside the BindToRenderStep, but setting the movement every frame according to where the character should be moving to, and running that loop outside, once:
local toggle = true
local RunService = game:GetService("RunService")
local humanoid = game.Players.LocalPlayer.Character:WaitForChild("Humanoid")
movement = nil
RunService:BindToRenderStep("Move", Enum.RenderPriority.Character.Value + 1, function()
if movement then
humanoid:Move(movement, true)
end
end)
while toggle do
movement = Vector3.new(0, 0, -1)
task.wait(1)
movement = Vector3.new(0, 0, 1)
task.wait(1)
end
movement = nil
Mind that this code has some quirks:
Nothing will be able to run after the while, so nothing will realistically set the toggle off if placed after while toggle do. It depends on where you want to switch the toggle how you'd handle this.
Depending on where you've placed this, it might error. If this is in StarterPlayerScripts you should use the CharacterAdded event to wait until the character exists, and then handle setting the humanoid again when respawning (because the humanoid will not be the same one if the character respawns). If this is in StarterCharacterScripts, there is no need to access the LocalPlayer, you can just do script.Parent:WaitForChild("Humanoid") (though it also comes down to personal preference).
You've made the movement relative to the camera with that true argument to :Move() https://create.roblox.com/docs/reference/engine/classes/Humanoid#Move. The player will still be able to move the camera to change how the movement direction.

I need help or atleast a pointer with collision in a game im making for fun

So I made a game, made a map, and everything is working fine. The problem is I made a very dumb collision system that worked first, but I am running into problems.
I am using player's X and Y positions to draw character, and using players tileX and tileY (x/32 and y/32) to detect collision. Heres a picture which explains my problem:
The Red box is players tileX and tileY cordinate.
Player still moves beyound the wall where the collision should happen.
The TileX doesnt let increases/decreases happen if they collide with a solid tile, BUT player's X and Y (sprite) still moves beyond that box for 31 more pixels. I have no idea how to fix this. My player image is not centered, its drawn on the top-right corner.
This is the current code im using:
for i=1, #lsx_map1 do
if math.floor(player.fx/32) == lsx_map1[i] and math.floor(player.fy/32) == lsy_map1[i] then
player.speedx = 0
player.speedy = 0
print("COLISSION DETECTED ON "..player.x.." "..player.y)
else
print(colVar)
colVar = colVar+1
end
end
if colVar == #lsx_map1 then
player.x = player.fx
player.y = player.fy
end
lsx_map1 is the number of solid tiles, and colVar should equal to that number if collision doesnt happen. In case collision happens, that number doesnt increase by one, and then nothing happens. Ask for any more details you need if you want to help me but you need more information.
Any help or tips would be appreciated. Thank you.

How to change the velocity in each frame in Love2D?

I'm trying to code a Pong game on Lua using the framework Love2D with some extra features. Among others, I want curves to occur. In order to do so, I'm trying to implement the trajectory of horizontally launched projectiles. I have a ball table with a position attribute for x (ball.x) and another for y (ball.y). I, also, have a an attribute for the x velocity (ball.dx) and another for the y velocity (ball.dy). Finally, I have an acceleration variable (gravity)
In my game, if the paddle moves and the ball hits it, the ball should follow and horizontal curve. In order to create my curves, I want to change the y-axis velocity on each frame in order to make my ball move in an arc across the screen. The main issue that I have is that I don't know how to change this velocity in each frame in order to create the expected arc. The most recent attempt that I made was to create a while loop like the following code. However, it creates an infinite loop. Can someone enlighten me please?
Clarification:
-Player.x and player.y are the player coordinate
-Player2.x and Player2.y are the opponent coordinate
-This piece of code is inside another if statement detecting a collision. It is inside the love.update(dt) function.
Thank you so much!
if love.keyboard.isDown("up") and distanceBetween(ball.x,ball.y,player.x,player.y)>30 then
ball.dy=0
while CollisionDetector(ball.x,player2.x,ball.y,player2.y, player2.width,player2.height,ball.size)==false or ball.x>0 or ball.y-20>0 or ball.y+20<love.graphics.getHeight() do
ball.dy=ball.dy+gravity*dt
ball.y=ball.y+ball.dy
end
end
I believe the snippet you've provided is a part of love.update function. (At least it should be.) That function is supposed to perform a single step of the game at a time and return. It is not supposed to handle the whole flight in a single call.
In your particular case, while loop expects the ball to move, but that is not something that will happen until the loop and encompassing function end.
In general, to simulate ongoing processes you'll have to store the information about such process. For example, if you want gravity be dependent on the paddle movement direction, then you'll have to modify the corresponding variable and store it between the call.
In your code, there are multiple other design flaws that make it do not what you think it should do. With some functions and code parts left to be implemented by yourself, the code outline would look as follows:
function collides(ball,player)
return (ball.x,player.x,ball.y,player.y, player.width,player.height,ball.size)
end
function love.update(dt)
handle_paddle_movements()
--handle the ball-paddle interaction
if collides(ball,player1) or collides(ball,player2) then
ball.dx=-ball.dx
if love.keyboard.isDown("up") then
--store the info you need to know about the interaction
ball.d2y = -gravity
else if love.keyboard.isDown("down")
ball.d2y = gravity
else
ball.d2y = 0
end
end
handle_the_wall_collision()
--ball movement code should be separate from collision handling
--concrete equations can be whatever you want
ball.x = ball.x+ball.dx*dt
ball.dy = ball.dy + ball.d2y * dt
ball.y = ball.y + ball.dy * dt
end

How to prevent unlimited jump in game? Corona LUA

okay so I have a jump button and a runtime listener function for when the jump button is pressed.
So whenver the jump button is pressed I apply linear impulse to the game hero.
local function controls(event)
if(event.phase=="began") then
if (buttonpressed.id=="jump") then
hero:applyLinearImpulse(0,-10,hero.x,hero.y)
end
elseif(event.phase=="ended") then
end
end
Now problem is if if the user keeps on tapping the jump button then the hero keeps on going up. I cant think of anyhting to counter this. One thing I could do is change the above code to:
local function controls(event)
if(event.phase=="began") then
if (buttonpressed.id=="jump" and hero.y>display.contentHeight/2) then
hero:applyLinearImpulse(0,-10,hero.x,hero.y)
end
elseif(event.phase=="ended") then
end
end
But this would still allow the jumping button to work until half of the screen is reached.
Kindly help me on this.
Thanks
Add a jump counter that resets when the player collides with the floor, that way you can allow double jumps etc later if you want to.
You could check the velocity of the hero and only allow the jump if the velocity is below a certain threshold:
if (buttonpressed.id=="jump" and hero.y>display.contentHeight/2) then
local vx, vy = hero:getLinearVelocity()
if vy < velocity_threshold then -- you have to define this value
hero:applyLinearImpulse(0,-10,hero.x,hero.y)
end
end
This should work. Another approach could be (i don't know much about corona) using linearDamping. This results in a damping of the linear motion, which sounds like something you could need.
You can also create a Boolean.
When the jump begins the boolean is true.
When the player collides with the floor is false.
While the boolean is true you cannot jump again.

Corona SDK Lua, How do I make a finger drawing/painting app?

I am fairly new to Lua and I have written the following code.
display.setStatusBar(display.HiddenStatusBar)
--Create the 'brush'
function paint(event)
locationX = event.x
locationY = event.y
brush = display.newCircle(locationX, locationY, 5)
end
Runtime:addEventListener("touch", paint)
All it does places a circle on the screen every time the paint function is invoked as long as the mouse has been clicked/held. However, the faster I move my mouse (I'm using Corona SDK) the more spaced out the circles become and it interrupts the flow of the line.
How could I change this so it draws a fluent line with no breaks?
Based on your code, what you're doing there is just putting a circle (hence the display.newCircle) whenever a touch event is triggered. The touch event is triggered when you start touching the screen (click of mouse in simulator), when you move your finger on the screen, and when you unclick or take your finger off of the screen.
In your case, you are putting a circle 5 pixels in size where you first touch the screen, where ever the finger is moving, and where you lift your finger/mouse off of the screen. Your problem comes during the finger moving phase or when event.phase = "moved". This occurs because the number of touch events you get during the movement is limited depending on the hardware you use. Therefore, if the movement is large enough, you will have places in between your placed circles where your touch event, or the function paint in your case, was not called due to this limitation.
If you just want a line, one way you might do this is to use the newLine method instead of the newCircle method. You would have to separate your touch inputs to their different phases, "began", "moved", "ended". During the "began" phase you would initiate your new line. During the "moved" or "ended" phase, you create (using newLine function) or add to your existing line with the append function.
I have not tested this code, but it may look something like this:
local line --variable to hold the line object
local initX --initial X coordinate of touch
local initY --initial Y coordinate of touch
local lineCreated = false --Flag to check if line is already created
--Create the 'brush'
function paint(event)
locationX = event.x
locationY = event.y
if event.phase == "began" then --first touch
--Delete previous line (in this case no multiple lines)
if(line) then
line:removeSelf()
line = nil
end
--Set initX and initY with current touch location
initX = locationX
initY = locationY
elseif event.phase == "moved" then --during touch movement
if lineCreated then
--line has been created, just append to existing line
line:append(locationX, locationY)
else
--Line has not been created
--Make new line object, set color, and stroke width
line = display.newLine(initX, initY, locationX, locationY)
line:setStrokeColor( 0, 0, 1 )
line.strokeWidth = 5
--set line created flag to true
lineCreated = true
end
elseif event.phase == "ended" or event.phase == "cancelled" then --touch lifted
--append last touch location to the line
line:append(locationX, locationY)
end
return true
end
Runtime:addEventListener("touch", paint)
This is a basic line so the corners may not be smooth. To make smooth lines you would need to apply algorithms that's a bit more complicated such as Bezier curve. There are many discussions on this for other programming languanges (the important thing is the algorithm, you can adopt it for Corona easily when you get more familiar with Lua, Lua is a relatively easy language to learn). You can get the math path here, and one source for Corona can be found here.

Resources