Best approach to restrict player movement to grid / XY axis

I’m toying with different ideas for my first game (be gentle). The level is made of squares that change colour when the player makes contact with them. However, what I’d like to do is prevent diagonal movements and keep the player moving along the x and y only. I have fixed the camera. Ideally, the movement would feel locked to the squares position. Always finishing central to a square.

What would be the best approach (some might not even be possible)? Some initial thoughts are;

1, invisible walls between squares
2, disable/ignore controller inputs other than up down left right (rounding to nearest for touch screen) + move player to nearest square centre when input ends.
3, click/touch part to walk there, disabling parts not aligned with x or y axis
4, lock player to x/y axis some other way

If anyone knows of similar examples on Roblox of what Im trying to achieve that would be great too!

Jay

4 Likes

I personally like option 2 when it comes to grid based games. It tends to feel the most natural. However depending on the style of game, option 3 might be better with pathfinding.

Thanks @tlr22 Click to walk might feel a bit clunky as Im not intending to to be puzzle type game. (However, I am going to do some reading up on pathfinding)

Is InputObject the correct API should I look into for modifying the players inputs / control? In simple terms Im thinking I need to; stop normal movement, detect which square nearest the player is one their direction input is “pointing at”, make player Humanoid:MoveTo the centre of that square.

Hi,

I am not a programmer but let me try, I feel like assigning keybinds to move 1 square at a time would be the best way? That way you can also avoid diagonal movement.

Let me know what you think about this.

Whoops, didn't see that you wanted to prevent Diagonal movement... That I don't really know how to do. Though I'm interested in finding out myself if somebody tells you :P

Do you mean the x / z axis? (y is ‘up and down’)
I think it’s fairly easy to just code the controls yourself and leave out the ability to jump.

(relevant tutorials on the wiki.
https://developer.roblox.com/en-us/articles/Side-Scrolling-Camera-View
https://developer.roblox.com/en-us/articles/Top-Down-Action-Controls)

I’ve had problems with restricting my characters to the X/Y axis for my sidescroller game, the characters always managed to get off the area they were supposed to be. . . (Due to the fact that when you turn, your character may slide a little)

1 Like

If you’re planning to make each area of movement be custom as you have it in the photo. Then generally (brace yourself for the bad terminology) Kind of like pathways I’d use a node based movement system. Basically when you press any button to move, instead of moving in that direction, I’d just move to the closest node in that direction. That way if I wanted to move it based on a grid, I could just generate a grid of nodes. (Using the Collection Service would be great here) then basically you’d move to the CFrame of that node. I’d avoid transparency though, either go full 0 transparency or full opaque.

Was pretty fun to think about this for the first time.

1 Like

Thank you for your input everyone! Glad you found it fun @T0ny

Here is what I plan to try and do - deep breath :slight_smile:

  • position a part in the workspace with its front face pointing away from the camera - our “North”
  • place the humanoid on one of the squares making up the grid
  • rotate him to face “north” - the same way as our reference part
  • detect which key is pressed to get the degree of rotation from “North”;
    UP = 0° rotation
    LEFT = 90° rotation
    RIGHT = -90° rotation
    DOWN = 180° rotation
  • get the CFrame of the point X degrees rotation and 1x length of grid square away from the humanoid - our TARGET
  • loop through the positions of the squares of the grid and find the nearest
  • Then make the humanoid walk to the the position of that square

How does that sound? It is the " get the CFrame of the point X degrees rotation and 1x length of grid square away…" part Im most unsure about.

Am I over complicating this? Kind of hoping there is some secret method I don’t know about yet.

3 Likes

Honestly, it doesn’t sound over complicated at all. Definitely a lot more efficient than my implementation. Also while the rotation bit is somewhat extra I believe it’s necessary to get the effect you’re looking for by adding it.

Instead of moving this extra part by a specific length, you should snap it like you would snap anything to a regular grid based on a grid size for it to be more uniform across the board. Honestly you could probably get away with just this without any loops at all. Though in my mind this implementation needs a confirmation to actually move to the target point. While the buttons you press would be moving that part you’re talking about.

Great adaptation. Also a type of controller I don’t commonly see on Roblox if at all.

Agreed. This is why using I would use the length just to get the “Target” and move the player to the grid square closest to the target.

Do you know which method might help with getting the CFrame of the point X degrees rotation and 1x length of grid square away? I’m new to vectors and CFrame :thinking:

a type of controller I don’t commonly see on Roblox if at all

:woozy_face: I hoping that’s a good thing

:thinking:

local squareLength = 8
local plr = game.Players.LocalPlayer
local character = plr.Character or plr.CharacterAdded:Wait()
-- rotate Humanoid as per control input
local IdealTarget = character.HumanoidRootPart.CFrame*CFrame.new(0,0,squareLength)
-- walkTo square of grid nearest to IdealTarget

There’s a good way to do this mathematically @EmilyBendsSpace has explained it to me probably more than once but :sob: lol. She could probably do a better job than me if you want that route.

But I don’t see the problem with just making a new CFrame originating at the humanoid root part with the lookVector being the target part’s position.

1 Like

I think this case is simple enough that what we discussed isn’t needed. The adjacent grid squares are always just +/- 1 grid unit away in either the X or Z world direction.

What I’d probably try first is a simple rule system:

  1. Detect if the player is near the center of a tile (e.g. their humanoid root part XZ location is within some tolerance distance of the tile’s XZ location)
  2. If the player is in the center of a tile, let them start moving along either the X axis, or the Z axis. But not both at the same time.
  3. As soon as the player is out of range of the center of the tile, whichever axis they walked along is locked in as the only axis they can move along until they reach the center of a tile again.

So basically, being at the center of a tile means you can choose to walk East-West or North-South. Any time you’re between tiles, you can only walk the path between them.

You can constrain player movement by modifying their MoveVector to only be (1,0,0), (-1,0,0), (0,0,1) or (0,0,-1). On mobile and console, variable walking speed is possible, so the values I’m showing here as 1 could be anything in the range [-1,1], the key is that the moveVector only ever has one non-zero component, either the X or Z.

3 Likes

if I’m correct this would allow the player to keep fluid control over the character but simply be constrained to a specific axis? What’s the reasoning behind choosing this route if you don’t mind me asking? My way wasn’t really preserving that fluidity of the controls.

As a refinement, to make the controller feel better, you could make a generous “center” allowance, and instead of setting moveVector to have just +/-1 in the X or Z direction, you could add a small correction on the perpendicular axis (the one they are not walking along), to steer them to be exactly on the grid line. You could then make the center detection area of the tile generously large, and it would allow players to cut the corners a bit. It would make T intersections feel better, because you wouldn’t have to get exactly in the center of a tile to take the 90-degree path rather than go straight through the T.

It depends on how movement is meant to feel. If it’s supposed to be more board game-like, you could also forcibly stop the player any time they reached a tile center, giving them a moment to change course before resuming. Or even force them to re-press the directional input key.

Wow. I’m going to need a few reads to get my head around this but thank you so much. I think I follow your explanation and it sounds great.

1 Like

I do like the idea of the player feeling more responsive despite the direction restriction. My solution might feel more like your “setting a course” than “controlling”

1 Like

In fact most of https://developer.roblox.com seems broken right now :sad:

I’m currently seeing a blank page(?) for the api. Is moveVector a property of humanoid?

Thanks for your input @EmilyBendsSpace! I think I have implemented the approach in your first suggestion. I imagine the code is super clunky but it does perform with the desired result so I have marked as solved.

However, I think your foresight about a refinement being necessary is now apparent so I’ve created a post on the scripting support forum.

Thanks

1 Like