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!
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.
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)
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.
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
a type of controller I don’t commonly see on Roblox if at all
I hoping that’s a good thing
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
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:
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)
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.
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.
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.
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.