- Home /
Getting maze walls (using 3D meshes) to work?
So I'm learning Unity by making a Pac-man clone, and I'm using 3D meshes to make both the walls and the player - but haven't yet been able to make them behave right. :)
I started with two Unity Cube Meshes, with the default box Collider - one Cube is scaled out into a Wall, and the other Cube is given a movement script (and locked to the Z-axis). It doesn't work - the Player goes right through the Wall. :) So after some research, I added a Rigidbody to the Player Cube. I turned gravity off, and freeze rotation.
This mostly works - the Player stops at the wall, but if I keep pressing arrow keys, it keeps trying to move, and vibrates back and forth. When I let go of the keys, it then has a small backwards force on it, going away from the Wall.
What do I need to change, to make it behave more like Pac-man? Are there any options I can adjust, to make the character stop instantly at the wall? Or does it require something like Raycasting to not even touch the wall?
And how do I stop the Cube from retreating from the Wall? Is this an AI problem? ;)
Update: code, changed to FixedUpdate, as per Tetrad:
void FixedUpdate() {
movePlayer();
}
void movePlayer() {
float xMove = Input.GetAxis("Horizontal") * playerSpeed * Time.deltaTime;
float yMove = Input.GetAxis("Vertical") * playerSpeed * Time.deltaTime;
Vector3 pos = this.transform.position;
Vector3 moveTo = new Vector3(pos.x + xMove, pos.y + yMove, origZ);
this.transform.position = moveTo;
}
Changing from Update() to FixedUpdate() stopped the vibrating effect - however the Player still goes slightly into the Wall, rebounding away when I stop pressing the movement keys.
Update 2: Current code (and it almost works) is:
void movePlayer() {
float curAxis = Input.GetAxis("Horizontal");
bool keyLeft = (curAxis < -0.01f);
bool keyRight = (curAxis > 0.01f);
if (curAxis == 0) {
isLeft = false;
isRight = false;
this.gameObject.rigidbody.velocity = Vector3.zero;
return;
}
else if (keyLeft && !isLeft) {
isLeft = true;
isRight = false;
this.gameObject.rigidbody.velocity = new Vector3(-baseSpeed, 0, 0);
// this.gameObject.rigidbody.AddForce(
// new Vector3(-baseSpeed, 0, 0), ForceMode.VelocityChange);
}
else if (keyRight && !isRight) {
isLeft = false;
isRight = true;
this.gameObject.rigidbody.velocity = new Vector3(baseSpeed, 0, 0);
// this.gameObject.rigidbody.AddForce(
// new Vector3(baseSpeed, 0, 0), ForceMode.VelocityChange);
}
}
It has two problems - first, sometimes when the Player collides with the Wall, it drops down a couple of pixels (and stays there). Second, it doesn't stop the instant I release the arrow keys. I don't understand how Forces work, but I would have thought that setting velocity=0 would stop it instantly. I'm also curious if there's a difference in setting velocity directly, versus the (commented out) AddForce(VelocityChange), which seems to behave identically.
Update 3: Apparently it's time to switch to Plan B: disregarding physics. Or as Vaarsuvius would say, "I consider the Laws of Physics as loose guidelines, at best." There were several good suggestions on how to approach the problem, and I wish I could checkmark more than one solution. :) Since I can't, @Tetrad actually gave the best answer (in a comment, no less) to the Question that I originally asked - how to make a Rigidbody behave.
There's really nothing specific about this problem that makes it a "2d problem". Doing it this way is just a collision behavior problem. It will also be difficult to provide suggestions without seeing what movement code you're using (i.e. are you moving your rigidbody in Update
ins$$anonymous$$d of FixedUpdate
).
@Tetrad, thanks, that partially fixed things. You should upgrade comment to Answer. :)
Answer by Tetrad · Jun 24, 2010 at 06:54 PM
If you're going to be doing your movement manually (i.e position += velocity * deltaTime ), you'll want to do a trace to make sure the position you're moving into isn't going to be inside a wall.
You're calculating a positional delta for that frame, and just hammering the position, which means he's intercepting the collider of the wall. When you let up on the input, the physics system pushes him out of the wall, which is why you're seeing the problems you describe.
You really have two options:
1) Use physics, and do something like setting your rigidbody velocity to control movement instead of hammering position directly. That way the internal physics system will know when to stop, and how to react to collisions (i.e. bounce/slide/etc). This is going to be the easiest solution, and also more indicative how how Unity games in general should be made.
2) Bypass physics entirely, and do a trace to make sure your next position isn't going to be in a wall. This is a complicated problem, and if you wanted to do things like slide along walls it will require a lot more math. It's definitely a solvable problem, but I wouldn't recommend it to somebody who doesn't have a firm grasp of collision/vector math. I can go into more detail on that if you really want.
@Tetrad, the reason I am doing manual movement, that's what I used in some other demo projects for a CharacterController, and when I started this project, I just copied the code over. :) But the way I interpret what you're saying, is I made it a weird, Frankenstein-type hybrid that doesn't work well either way. :) So I should use the keyboard inputs to apply a force to the player, and let the system handle it? I presume it would be a binary thing, on when key down, off otherwise, so as to get consistent speed?
re: hybrid that doesn't work well, yes. For the second question, there are a couple of ways of doing it. You can either set the rigid body velocity directly (which you could make a binary movement thing, or you could tween the speed), or you can do something like what this script is doing: http://www.unifycommunity.com/wiki/index.php?title=RigidbodyFPSWalker where it adds forces to try to match your desired speed.
@Tetrad - well, it almost works as desired - I updated my OP with what is still going wrong.
@Tetrad, maybe I should be asking - is this really even feasible? Am I abusing the physics engine, to try and make it run as a purely deter$$anonymous$$istic model?
Answer by Facundo · Jun 24, 2010 at 05:27 PM
Just as a suggestion, don't try to detect collision of the pacman with the walls. Instead of that, constrain the movement of pacman to a line segment that runs through the center of the corridor from one fork to the next one.
That way, the pacman should move only while the pacman center stays on the line segment. I don't think Unity brings a ready to use solution for that, you may have to write your own code for it.
@Facundo, very interesting suggestion, I have to think about that. Although it wouldn't generalize to allow open space/free movement, I did say pac-man-like mazes.
Answer by Eric5h5 · Jun 25, 2010 at 10:23 PM
For an actual Pac-Man clone, I'd use an array for the maze, and not bother with physics at all. Then you just translate world positions to array positions, and not allow movement into "wall" array cells. For example, my iPhone maze game has no "real" collision detection, it's just a 3D array. You can also look at this script for 2D grid movement. It would need some modification for this case, such as adding the aforementioned "collision detection", and you'd want to be able to reverse direction immediately rather than only at the grid lines.
@Cyclops: depends on what you're making...I can't see using physics for a literal Pac-$$anonymous$$an clone; there's no point (among other things, the sprites never actually touch the walls). If you were making a different sort of 2D maze game that had a reason for using physics (maybe you could kill monsters by pushing them into the walls or something, I dunno), then by all means use the physics engine.
Answer by AnaRhisT · Jun 24, 2010 at 05:16 PM
There's really nothing specific about this problem that makes it a "2d problem". Doing it this way is just a collision behavior problem. It will also be difficult to provide suggestions without seeing what movement code you're using (i.e. are you moving your rigidbody in Update instead of FixedUpdate).
owned :)
Disowned - don't do that. :) And aside from the ethics, you posted after I updated my Question (with FixedUpdate), so this is totally irrelevant.
Your answer
Follow this Question
Related Questions
Colision And then Function update Help 1 Answer
Disabling objects from Collision detection 1 Answer
Terrain collision problem 1 Answer
Collision Enter one of the objects ? 1 Answer