Pokemon style movement
Pokemon style movement
Hello, I'm developing a game (novelty '__' ) and in this game, I'm trying to recreate the player's movement in the style of pokemon games, but I'm having a lot of difficulty writing it, I wanted to know how you would or did this mechanics in your game.
Thank you for helping me 'v'
Thank you for helping me 'v'
Code: Select all
-------------------------------
-- i love programming in Lua --
-------------------------------
Re: Pokemon style movement
Can you please explain the pokemon player movement system for people that have not played the pokemon?ATS wrote: ↑Sat Apr 09, 2022 9:00 pm Hello, I'm developing a game (novelty '__' ) and in this game, I'm trying to recreate the player's movement in the style of pokemon games, but I'm having a lot of difficulty writing it, I wanted to know how you would or did this mechanics in your game.
Thank you for helping me 'v'
- Hugues Ross
- Citizen
- Posts: 85
- Joined: Fri Oct 22, 2021 9:18 pm
- Location: Quebec
- Contact:
Re: Pokemon style movement
I'm assuming they mean the older tile-based games, as they had a somewhat distinct system. I can recall 2 main attributes:
- 4-directional movement locked to the tile grid (ie. once you start moving between tiles, you will continue until you reach the tile even if you drop the input)
- Tapping one of the directional inputs turns your character to face in a direction instead of immediately moving
Unless I'm forgetting something, both of these should be reasonably doable. For the former, I'd have two sets of coordinates per-object. The tile grid coordinate would control the actual movement and collision checks, while a second "world-space" coordinate controls the player's rendered position. When you get a directional input, start a very short timer and start moving when it elapses (if the button is held the whole time, you can do this by resetting the timer when the input is dropped). You could also have a check to skip the timer if the input is in the same direction as the player's facing, for quality-of-life.
Once movement starts, the player should instantly warp to the target position on the tile grid (if no collision, ofc). This prevents cases where two entities try to walk into the same square around the same time. Then, you just need to interpolate the player's world-space position to the new spot and repeat. For the facing, easiest option is probably assigning each direction to a key and converting to offset coordinates from that. You can re-use that same key with a second lookup to find the correct heading in a spritesheet too!
- 4-directional movement locked to the tile grid (ie. once you start moving between tiles, you will continue until you reach the tile even if you drop the input)
- Tapping one of the directional inputs turns your character to face in a direction instead of immediately moving
Unless I'm forgetting something, both of these should be reasonably doable. For the former, I'd have two sets of coordinates per-object. The tile grid coordinate would control the actual movement and collision checks, while a second "world-space" coordinate controls the player's rendered position. When you get a directional input, start a very short timer and start moving when it elapses (if the button is held the whole time, you can do this by resetting the timer when the input is dropped). You could also have a check to skip the timer if the input is in the same direction as the player's facing, for quality-of-life.
Once movement starts, the player should instantly warp to the target position on the tile grid (if no collision, ofc). This prevents cases where two entities try to walk into the same square around the same time. Then, you just need to interpolate the player's world-space position to the new spot and repeat. For the facing, easiest option is probably assigning each direction to a key and converting to offset coordinates from that. You can re-use that same key with a second lookup to find the correct heading in a spritesheet too!
Re: Pokemon style movement
You described it perfectly! If it's not too much trouble, could you show me some code with this mechanic in place? Because I wanted to have an idea or even understand how to make it work =)Hugues Ross wrote: ↑Sat Apr 09, 2022 11:14 pm I'm assuming they mean the older tile-based games, as they had a somewhat distinct system. I can recall 2 main attributes:
- 4-directional movement locked to the tile grid (ie. once you start moving between tiles, you will continue until you reach the tile even if you drop the input)
- Tapping one of the directional inputs turns your character to face in a direction instead of immediately moving
Unless I'm forgetting something, both of these should be reasonably doable. For the former, I'd have two sets of coordinates per-object. The tile grid coordinate would control the actual movement and collision checks, while a second "world-space" coordinate controls the player's rendered position. When you get a directional input, start a very short timer and start moving when it elapses (if the button is held the whole time, you can do this by resetting the timer when the input is dropped). You could also have a check to skip the timer if the input is in the same direction as the player's facing, for quality-of-life.
Once movement starts, the player should instantly warp to the target position on the tile grid (if no collision, ofc). This prevents cases where two entities try to walk into the same square around the same time. Then, you just need to interpolate the player's world-space position to the new spot and repeat. For the facing, easiest option is probably assigning each direction to a key and converting to offset coordinates from that. You can re-use that same key with a second lookup to find the correct heading in a spritesheet too!
Code: Select all
-------------------------------
-- i love programming in Lua --
-------------------------------
Re: Pokemon style movement
Read Hugues Ross' answer, he explained it perfectly.darkfrei wrote: ↑Sat Apr 09, 2022 10:44 pmCan you please explain the pokemon player movement system for people that have not played the pokemon?ATS wrote: ↑Sat Apr 09, 2022 9:00 pm Hello, I'm developing a game (novelty '__' ) and in this game, I'm trying to recreate the player's movement in the style of pokemon games, but I'm having a lot of difficulty writing it, I wanted to know how you would or did this mechanics in your game.
Thank you for helping me 'v'
![Ultrahappy :ultrahappy:](./images/smilies/ms-ultrahappy.png)
Code: Select all
-------------------------------
-- i love programming in Lua --
-------------------------------
- Hugues Ross
- Citizen
- Posts: 85
- Joined: Fri Oct 22, 2021 9:18 pm
- Location: Quebec
- Contact:
Re: Pokemon style movement
Sure! It isn't the cleanest implementation, but this demo I just threw together should help give you some ideas. It's a completely playable, so you can throw this into LÖVE and try it if you'd like.
Code: Select all
local tile_x,tile_y = 10,7 -- Player's tile position
local w,h = 32,32 -- Tile width/height in pixels
local x,y = tile_x*w,tile_y*h -- Player's pixel position
local heading = 1 -- The player's in-game heading direction
local key_heading = 0 -- The heading direction the player is holding
local turn_timer = 0 -- Timer for waiting after the player turns before moving
local turn_wait = 0.1 -- How long to wait after the player turns
-- Lookup to get the heading value from a keycode
local keys = {
left = 1,
right = 2,
up = 3,
down = 4,
}
-- Lookup to get a directional vector from a heading value
local heading_vectors = {
{ -1, 0 },
{ 1, 0 },
{ 0, -1 },
{ 0, 1 },
}
function love.keypressed(key, _, isrepeat)
if not isrepeat then
-- When the player presses a new directional key, change the heading
local dir = keys[key]
if dir and dir ~= key_heading then
key_heading = dir
end
end
end
function love.keyreleased(key, _)
-- When the player releases the current heading key, reset
local dir = keys[key]
if dir and dir == key_heading then
key_heading = 0
end
end
function love.update(dt)
if x / w ~= tile_x or x % w ~= 0 then
-- If the player's pixel position hasn't reached the tile position, keep moving
local dest = tile_x * w
local sign = (dest - x) / math.abs(dest - x)
x = x + (sign * 2)
elseif y / h ~= tile_y or y % h ~= 0 then
-- If the player's pixel position hasn't reached the tile position, keep moving
local dest = tile_y * h
local sign = (dest - y) / math.abs(dest - y)
y = y + (sign * 2)
else -- No need to move, handle input
if key_heading ~= 0 then -- Directional key is held down
-- If we need to turn, turn and start the timer
if key_heading ~= heading then
heading = key_heading
turn_timer = turn_wait
end
-- Decrement the turn timer
turn_timer = turn_timer - dt
-- If we're done waiting, warp the player to the next tile position
if turn_timer <= 0 then
turn_timer = 0
local vec = heading_vectors[heading]
tile_x = tile_x + vec[1]
tile_y = tile_y + vec[2]
end
end
end
end
function love.draw()
-- Checkerboard tiles
local window_w,window_h = love.graphics.getDimensions()
for i=0,math.ceil(window_w/w) do
for j=0,math.ceil(window_h/h) do
if (i + j) % 2 == 0 then
love.graphics.setColor(0.1,0.1,0.15)
love.graphics.rectangle("fill", i * w, j * h, w, h)
end
end
end
-- Draw the player
love.graphics.setColor(1,1,1)
love.graphics.rectangle("fill", x, y, w, h)
-- Draw the player's heading
local vec = heading_vectors[heading]
local offset_x = vec[1] * (w * 0.5) + 4
local offset_y = vec[2] * (h * 0.5) + 4
love.graphics.setColor(1,0,0)
love.graphics.rectangle("fill", x + (w * 0.5) + offset_x - 8, y + (h * 0.5) + offset_y - 8, 8, 8)
end
Re: Pokemon style movement
THAT'S RIGHT!!!! Thank you very much, you helped me a lotHugues Ross wrote: ↑Sun Apr 10, 2022 12:33 pmSure! It isn't the cleanest implementation, but this demo I just threw together should help give you some ideas. It's a completely playable, so you can throw this into LÖVE and try it if you'd like.
EDIT: Should also note that there's no collision-checking... it's easy to do though, you just compare two sets of tile coordinates and it's a hit if they're the same. For objects larger than 1 tile, you can probably do a point to AABB check using the tile coordinates & tile dimensions of the large object.Code: Select all
local tile_x,tile_y = 10,7 -- Player's tile position local w,h = 32,32 -- Tile width/height in pixels local x,y = tile_x*w,tile_y*h -- Player's pixel position local heading = 1 -- The player's in-game heading direction local key_heading = 0 -- The heading direction the player is holding local turn_timer = 0 -- Timer for waiting after the player turns before moving local turn_wait = 0.1 -- How long to wait after the player turns -- Lookup to get the heading value from a keycode local keys = { left = 1, right = 2, up = 3, down = 4, } -- Lookup to get a directional vector from a heading value local heading_vectors = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 }, } function love.keypressed(key, _, isrepeat) if not isrepeat then -- When the player presses a new directional key, change the heading local dir = keys[key] if dir and dir ~= key_heading then key_heading = dir end end end function love.keyreleased(key, _) -- When the player releases the current heading key, reset local dir = keys[key] if dir and dir == key_heading then key_heading = 0 end end function love.update(dt) if x / w ~= tile_x or x % w ~= 0 then -- If the player's pixel position hasn't reached the tile position, keep moving local dest = tile_x * w local sign = (dest - x) / math.abs(dest - x) x = x + (sign * 2) elseif y / h ~= tile_y or y % h ~= 0 then -- If the player's pixel position hasn't reached the tile position, keep moving local dest = tile_y * h local sign = (dest - y) / math.abs(dest - y) y = y + (sign * 2) else -- No need to move, handle input if key_heading ~= 0 then -- Directional key is held down -- If we need to turn, turn and start the timer if key_heading ~= heading then heading = key_heading turn_timer = turn_wait end -- Decrement the turn timer turn_timer = turn_timer - dt -- If we're done waiting, warp the player to the next tile position if turn_timer <= 0 then turn_timer = 0 local vec = heading_vectors[heading] tile_x = tile_x + vec[1] tile_y = tile_y + vec[2] end end end end function love.draw() -- Checkerboard tiles local window_w,window_h = love.graphics.getDimensions() for i=0,math.ceil(window_w/w) do for j=0,math.ceil(window_h/h) do if (i + j) % 2 == 0 then love.graphics.setColor(0.1,0.1,0.15) love.graphics.rectangle("fill", i * w, j * h, w, h) end end end -- Draw the player love.graphics.setColor(1,1,1) love.graphics.rectangle("fill", x, y, w, h) -- Draw the player's heading local vec = heading_vectors[heading] local offset_x = vec[1] * (w * 0.5) + 4 local offset_y = vec[2] * (h * 0.5) + 4 love.graphics.setColor(1,0,0) love.graphics.rectangle("fill", x + (w * 0.5) + offset_x - 8, y + (h * 0.5) + offset_y - 8, 8, 8) end
![Ultrahappy :ultrahappy:](./images/smilies/ms-ultrahappy.png)
![Ultrahappy :ultrahappy:](./images/smilies/ms-ultrahappy.png)
![Ultrahappy :ultrahappy:](./images/smilies/ms-ultrahappy.png)
![Ultrahappy :ultrahappy:](./images/smilies/ms-ultrahappy.png)
![Ultrahappy :ultrahappy:](./images/smilies/ms-ultrahappy.png)
Code: Select all
-------------------------------
-- i love programming in Lua --
-------------------------------
Re: Pokemon style movement
One more thing, I'm using the Windfield physics library and I'm having trouble colliding with this script you wrote, how can I solve this?Hugues Ross wrote: ↑Sun Apr 10, 2022 12:33 pmSure! It isn't the cleanest implementation, but this demo I just threw together should help give you some ideas. It's a completely playable, so you can throw this into LÖVE and try it if you'd like.
EDIT: Should also note that there's no collision-checking... it's easy to do though, you just compare two sets of tile coordinates and it's a hit if they're the same. For objects larger than 1 tile, you can probably do a point to AABB check using the tile coordinates & tile dimensions of the large object.Code: Select all
local tile_x,tile_y = 10,7 -- Player's tile position local w,h = 32,32 -- Tile width/height in pixels local x,y = tile_x*w,tile_y*h -- Player's pixel position local heading = 1 -- The player's in-game heading direction local key_heading = 0 -- The heading direction the player is holding local turn_timer = 0 -- Timer for waiting after the player turns before moving local turn_wait = 0.1 -- How long to wait after the player turns -- Lookup to get the heading value from a keycode local keys = { left = 1, right = 2, up = 3, down = 4, } -- Lookup to get a directional vector from a heading value local heading_vectors = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 }, } function love.keypressed(key, _, isrepeat) if not isrepeat then -- When the player presses a new directional key, change the heading local dir = keys[key] if dir and dir ~= key_heading then key_heading = dir end end end function love.keyreleased(key, _) -- When the player releases the current heading key, reset local dir = keys[key] if dir and dir == key_heading then key_heading = 0 end end function love.update(dt) if x / w ~= tile_x or x % w ~= 0 then -- If the player's pixel position hasn't reached the tile position, keep moving local dest = tile_x * w local sign = (dest - x) / math.abs(dest - x) x = x + (sign * 2) elseif y / h ~= tile_y or y % h ~= 0 then -- If the player's pixel position hasn't reached the tile position, keep moving local dest = tile_y * h local sign = (dest - y) / math.abs(dest - y) y = y + (sign * 2) else -- No need to move, handle input if key_heading ~= 0 then -- Directional key is held down -- If we need to turn, turn and start the timer if key_heading ~= heading then heading = key_heading turn_timer = turn_wait end -- Decrement the turn timer turn_timer = turn_timer - dt -- If we're done waiting, warp the player to the next tile position if turn_timer <= 0 then turn_timer = 0 local vec = heading_vectors[heading] tile_x = tile_x + vec[1] tile_y = tile_y + vec[2] end end end end function love.draw() -- Checkerboard tiles local window_w,window_h = love.graphics.getDimensions() for i=0,math.ceil(window_w/w) do for j=0,math.ceil(window_h/h) do if (i + j) % 2 == 0 then love.graphics.setColor(0.1,0.1,0.15) love.graphics.rectangle("fill", i * w, j * h, w, h) end end end -- Draw the player love.graphics.setColor(1,1,1) love.graphics.rectangle("fill", x, y, w, h) -- Draw the player's heading local vec = heading_vectors[heading] local offset_x = vec[1] * (w * 0.5) + 4 local offset_y = vec[2] * (h * 0.5) + 4 love.graphics.setColor(1,0,0) love.graphics.rectangle("fill", x + (w * 0.5) + offset_x - 8, y + (h * 0.5) + offset_y - 8, 8, 8) end
Code: Select all
-------------------------------
-- i love programming in Lua --
-------------------------------
- Hugues Ross
- Citizen
- Posts: 85
- Joined: Fri Oct 22, 2021 9:18 pm
- Location: Quebec
- Contact:
Re: Pokemon style movement
Unfortunately, I've never used that library. You'll have to check with someone else!
Re: Pokemon style movement
ok thank you so much for helping meHugues Ross wrote: ↑Sun Apr 10, 2022 4:59 pm Unfortunately, I've never used that library. You'll have to check with someone else!
![Wink ;)](./images/smilies/ms-wink.png)
Code: Select all
-------------------------------
-- i love programming in Lua --
-------------------------------
Who is online
Users browsing this forum: No registered users and 62 guests