I am creating a pacman game using noobtuts' tutorial. https://noobtuts.com/unity/2d-pacman-game However I want to make pacman to be able move on its own. My idea is to make it choose a random direction to move, and it will head into that direction if it is a valid move. How should I do it? Appreciate any answers!
This is noobtuts' code that moves pacman with user input.
Vector2 dest = Vector2.zero;
void Start()
{
dest = transform.position;
disabled = false;
}
void FixedUpdate()
{
// Move closer to Destination
Vector2 p = Vector2.MoveTowards(transform.position, dest, speed);
GetComponent<Rigidbody2D>().MovePosition(p);
// Check for Input if not moving
if ((Vector2)transform.position == dest && !disabled)
{
if (DirectionEmulator.direction == "up" && valid(Vector2.up))
dest = (Vector2)transform.position + Vector2.up;
if (DirectionEmulator.direction == "right" && valid(Vector2.right))
dest = (Vector2)transform.position + Vector2.right;
if (DirectionEmulator.direction == "down" && valid(-Vector2.up))
dest = (Vector2)transform.position - Vector2.up;
if (DirectionEmulator.direction == "left" && valid(-Vector2.right))
dest = (Vector2)transform.position - Vector2.right;
}
// Animation Parameters
Vector2 dir = dest - (Vector2)transform.position;
GetComponent<Animator>().SetFloat("DirX", dir.x);
GetComponent<Animator>().SetFloat("DirY", dir.y);
}
bool valid(Vector2 dir)
{
// Cast Line from 'next to Pac-Man' to 'Pac-Man'
Vector2 pos = transform.position;
RaycastHit2D hit = Physics2D.Linecast(pos + dir, pos);
return (hit.collider == GetComponent<Collider2D>());
}
I managed to make it work as of now, but I believe much more can be improved. Please provide any input if you have any solutions!
private string move;
Vector2 dest = Vector2.zero;
void Start()
{
dest = transform.position;
disabled = false;
move = "right";
}
void FixedUpdate() //use this to decide movement
{
// Move closer to Destination
Vector2 p = Vector2.MoveTowards(transform.position, dest, speed);
GetComponent<Rigidbody2D>().MovePosition(p);
// determine next destination
if ((Vector2)transform.position == dest && !disabled)
{
//check valid direction
if (move == "up" && valid(Vector2.up))
{
dest = (Vector2)transform.position + Vector2.up;
}
if (move == "right" && valid(Vector2.right))
{
dest = (Vector2)transform.position + Vector2.right;
}
if (move == "down" && valid(-Vector2.up))
{
dest = (Vector2)transform.position - Vector2.up;
}
if (move == "left" && valid(-Vector2.right))
{
dest = (Vector2)transform.position - Vector2.right;
}
//if not valid, change direction
// choose random valid direction
System.Random rnd = new System.Random();
int rand = rnd.Next(1, 4);
if (rand == 1 && valid(Vector2.up))
{
move = "up";
}
else if (rand == 2 && valid(Vector2.right))
{
move = "right";
}
else if (rand == 3 && valid(-Vector2.up))
{
move = "down";
}
else if (rand == 4 && valid(-Vector2.right))
{
move = "left";
}
}
// Animation Parameters
Vector2 dir = dest - (Vector2)transform.position;
GetComponent<Animator>().SetFloat("DirX", dir.x);
GetComponent<Animator>().SetFloat("DirY", dir.y);
}
bool valid(Vector2 dir)
{
// Cast Line from 'next to Pac-Man' to 'Pac-Man'
Vector2 pos = transform.position;
RaycastHit2D hit = Physics2D.Linecast(pos + dir, pos);
return (hit.collider == GetComponent<Collider2D>());
}
Related
Got a problem with my code (on Unity 2D).
I'm trying to make a PacMan like for my class, and my PacMan doesn't want to move at all.
He's animated but he's not moving.
public class PacmanMove : MonoBehaviour {
public float speed = 0.4f;
Vector2 dest = Vector2.zero;
void Start() {
dest = transform.position;
}
void FixedUpdate() {
// Move closer to Destination
Vector2 p = Vector2.MoveTowards(transform.position, dest, speed);
GetComponent<Rigidbody2D>().MovePosition(p);
// Check for Input if not moving
if ((Vector2)transform.position == dest) {
if (Input.GetKey(KeyCode.UpArrow) && valid(Vector2.up))
dest = (Vector2)transform.position + Vector2.up;
if (Input.GetKey(KeyCode.RightArrow) && valid(Vector2.right))
dest = (Vector2)transform.position + Vector2.right;
if (Input.GetKey(KeyCode.DownArrow) && valid(-Vector2.up))
dest = (Vector2)transform.position - Vector2.up;
if (Input.GetKey(KeyCode.LeftArrow) && valid(-Vector2.right))
dest = (Vector2)transform.position - Vector2.right;
}
}
bool valid(Vector2 dir) {
// Cast Line from 'next to Pac-Man' to 'Pac-Man'
Vector2 pos = transform.position;
RaycastHit2D hit = Physics2D.Linecast(pos + dir, pos);
return (hit.collider == GetComponent<Collider2D>());
}
}
Please help me :)
If you don't have to use physics, you can use this.
void FixedUpdate() {
// Check for Input if not moving
if ((Vector2)transform.position == dest) {
if (Input.GetKey(KeyCode.UpArrow) && valid(Vector2.up))
dest = (Vector2)transform.position + Vector2.up;
if (Input.GetKey(KeyCode.RightArrow) && valid(Vector2.right))
dest = (Vector2)transform.position + Vector2.right;
if (Input.GetKey(KeyCode.DownArrow) && valid(-Vector2.up))
dest = (Vector2)transform.position - Vector2.up;
if (Input.GetKey(KeyCode.LeftArrow) && valid(-Vector2.right))
dest = (Vector2)transform.position - Vector2.right;
}
else
{
// Move closer to Destination
transform.position = Vector2.MoveTowards(transform.position, dest, speed);
}
}
Ok, the problem wasn't in the code, it was on my Object's configuration
If you have the same problem, check out if your Object's gravity is on 0 :)
so I have a script that rotates a cube (by 90 degrees when a direction is pressed) currently im using the oncollision enter to detect walls and when I try to use it to also check if grounded then it will just completely stop everything when i leave one collision and enter another, or it won't fully check when im in mid air and will allow me to move when i don't want to be able to. Any and all help is greatly appreciated.
{
bool isGrounded = true;
private Rigidbody2D rb;
bool leftInput = true;
bool rightInput = true;
public float RollingDuration = 0.2f;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
// fixed update is for physics
void FixedUpdate()
{
var dir = Vector3.zero;
if (Input.GetKey(KeyCode.LeftArrow) && leftInput && isGrounded)
{
dir = Vector3.left;
}
if (Input.GetKey(KeyCode.RightArrow) && rightInput && isGrounded)
{
dir = Vector3.right;
}
if (dir !=Vector3.zero && !isRolling)
{
StartCoroutine(Roll(dir));
}
}
private void OnCollisionEnter2D(Collision2D collision)
{
//check to see if our player is grounded
if (collision.gameObject.tag == "Grounded")
{
isGrounded = true;
}
if (collision.gameObject.tag == "LeftWall" || collision.gameObject.tag == "RightWall")
{
StopCoroutine("Roll");
if (collision.gameObject.tag == "LeftWall")
{
leftInput = false;
// we are grounded when touching walls
isGrounded = true;
}
if (collision.gameObject.tag == "RightWall")
{
rightInput = false;
// we are grounded when touching walls
isGrounded = true;
}
if (collision.gameObject.tag == null)
{
isGrounded = false;
}
else
{
isRolling = false;
rb.velocity = Vector2.zero;
rb.velocity = new Vector2(0.0f, 0.0f);
rb.angularVelocity = 0.0f;
rb.transform.rotation = Quaternion.Euler(0.0f, 0.0f, 0.0f);
rb.rotation = 0.0f;
}
}
}
bool isRolling = false;
IEnumerator Roll(Vector3 direction)
{
if (direction == Vector3.right && isGrounded)
{
leftInput = true;
}
else if (direction == Vector3.left && isGrounded)
{
rightInput = true;
}
isRolling = true;
var rotAxis = Vector3.Cross(Vector3.up, direction);
var pivot = (rb.transform.position + Vector3.down * 0.5f) + direction * 0.5f;
var startRotation = rb.transform.rotation;
var endRotation = Quaternion.AngleAxis(90.0f, rotAxis) * startRotation;
var startPosition = rb.transform.position;
var endPosition = rb.transform.position + direction;
var rotSpeed = 90.0f / RollingDuration;
var t = 0.0f;
while (t < RollingDuration && isGrounded)
{
t += Time.deltaTime;
if (t < RollingDuration && isGrounded)
{
rb.transform.RotateAround(pivot, rotAxis, rotSpeed * Time.deltaTime);
yield return null;
}
else
{
rb.transform.rotation = endRotation;
rb.transform.position = endPosition;
}
}
isRolling = false;
}
}
I think the most simple and common way to do ground checks is with casting a ray. So just cast a ray into the direction you want to check or try Overlap functions.
Example:
if(Physics.OverlapCircle(point, radius, layerMask)) {
//do stuff
}
So just cast a ray in all direction you want to check or add a overlap function to each side of the cube.
It started happening after I wrote the script for dashing. Now, whenever I dash into walls, my character gets stuck to that wall. If I dash towards the roof, then I can walk on the roof for example. Also, when I dash next to a wall / on the floor, it never stops dashing after a single press. Any help will be appreciated, thanks.
The code below is the dashing script, if needed I can post the variables set and my character controller script too.
void Start()
{
_rigidbody = GetComponent<Rigidbody2D>();
dashTime = baseDashTime;
}
void Update()
{
isGrounded = Physics2D.OverlapCircle(feet.position, checkRadius, checkGround);
if(isGrounded == true)
{
dashTime = baseDashTime;
}
if (direction == 0)
{
if (Input.GetKey(KeyCode.W) && (Input.GetKeyDown(KeyCode.LeftShift)))
{
direction = 1;
}
else if (Input.GetKey(KeyCode.A) && (Input.GetKeyDown(KeyCode.LeftShift)))
{
direction = 2;
}
else if (Input.GetKey(KeyCode.S) && (Input.GetKeyDown(KeyCode.LeftShift)))
{
direction = 3;
}
else if (Input.GetKey(KeyCode.D) && (Input.GetKeyDown(KeyCode.LeftShift)))
{
direction = 4;
}
}
else
{
if (dashTime <= 0)
{
direction = 0;
_rigidbody.velocity = Vector2.zero;
}
else
{
dashTime -= Time.deltaTime;
if (direction == 1)
{
_rigidbody.velocity = Vector2.up * dashSpeed;
}
else if (direction == 2)
{
_rigidbody.velocity = Vector2.left * dashSpeed;
}
else if (direction == 3)
{
_rigidbody.velocity = Vector2.down * dashSpeed;
}
else if (direction == 4)
{
_rigidbody.velocity = Vector2.right * dashSpeed;
}
}
}
}
In your code you have this statement in the update function. When you dash on the ground, im guessing IsGrounded will stay true, so the player will keep dashing forever. This is probably what causes the player to be stuck.
if(isGrounded == true)
{
dashTime = baseDashTime;
}
I am trying to make a player spaceship move between three points when the user enters left or right on the keyboard. I would like the player to move smoothly between these points but it seems that the Lerp function is only interpolated once.
Here is the Game master script which checks for input from the user and passes it onto the Player controller which performs the Lerp:
Game master:
void Update ()
{
if (gameIsRunning)
{
if (Input.GetKeyDown(KeyCode.A))
{
//Go Left
player.MovePlayer("left");
}
else if (Input.GetKeyDown(KeyCode.D))
{
//Go Right
player.MovePlayer("right");
}
//Only run this if the game is running...
if (player.Lives <= 0)
{
gameIsRunning = false;
}
}
}
Player controller:
public void MovePlayer (string dir)
{
if (dir == "left")
{
if (currentPosition == Position.Left)
{
//Do Nothing!
return;
}
if (currentPosition == Position.Middle)
{
transform.position = Vector3.Lerp(middlePos.position, leftPos.position, .5f);
currentPosition = Position.Left;
}
if (currentPosition == Position.Right)
{
transform.position = Vector3.Lerp(rightPos.position, middlePos.position, .5f);
currentPosition = Position.Middle;
}
}
if (dir == "right")
{
if (currentPosition == Position.Right)
{
//Do Nothing!
return;
}
if (currentPosition == Position.Middle)
{
transform.position = Vector3.Lerp(transform.position, rightPos.position, .5f);
currentPosition = Position.Right;
}
if (currentPosition == Position.Left)
{
transform.position = Vector3.Lerp(transform.position, middlePos.position, .5f);
currentPosition = Position.Middle;
}
}
}
Screenshot:
Why is this happening?
lerp must be called with a changing parameter. try something like:
Player controller:
enum Direction
{
Left,
Right
}
Direction moveDir;
float progress;
public void MovePlayer (Direction dir)
{
moveDir = dir;
progress = 0.0f;
}
public void Update()
{
switch(dir)
{
case Direction.Left:
if (currentPosition == Position.Middle)
{
transform.position = Vector3.Lerp(middlePos.position, leftPos.position, progress);
if(progress >= 1.0f)
currentPosition = Position.Left;
else
progress += 0.1f; // change as necessary
}
if (currentPosition == Position.Right)
{
transform.position = Vector3.Lerp(rightPos.position, middlePos.position, progress);
if(progress >= 1.0f)
currentPosition = Position.Middle;
else
progress += 0.1f; // change as necessary
}
break;
case Direction.Right:
// ...
break;
}
}
I have a camera in my scene I am controlling with a third party device. If I spin the device, pitch it forward etc the same action is replicated with my camera. However, I'm stuck working out how to always make sure my camera is facing forward and moving forward in spite of its Y rotation.
For example, my camera starts at point 0,0,0 with the same rotation value. If I rotate my camera 90 degrees (either side) and move my camera forward, my view now moves side ways. How can I get it so that where ever my camera is facing, that is my forward direction?
Here is my code so far:
private void MoveForward()
{
Debug.Log("yaw: " + yaw + " pitch: " + pitch + " roll: " + roll);
if( pitch > maxPitch.x && pitch < maxPitch.y && reversePitch == false)
{
camera.rigidbody.AddForce(0, 0,-pitch);
// camera.transform.position += new Vector3(0,0, -pitch);
}
else if ( pitch > maxPitch.x && pitch < maxPitch.y && reversePitch == true)
{
camera.rigidbody.AddForce(0, 0, pitch);
// camera.transform.position += new Vector3(0,0, pitch);
}
else
{
camera.rigidbody.velocity = Vector3.zero;
// camera.transform.position = new Vector3(0,0,0);
}
}
private void MoveSideways()
{
if( roll > maxRoll.x && roll < maxRoll.y && reverseRoll == false)
{
camera.rigidbody.AddForce( roll, 0, 0);
}
else if ( roll < maxRoll.x && roll > maxRollNegative && reverseRoll == false)
{
camera.rigidbody.AddForce( roll, 0 ,0);
}
else if( roll > maxRoll.x && roll < maxRoll.y && reverseRoll == true)
{
camera.rigidbody.AddForce( -roll, 0, 0);
}
else if ( roll < maxRoll.x && roll > maxRollNegative && reverseRoll == true)
{
camera.rigidbody.AddForce( -roll, 0 ,0);
}
else
{
camera.rigidbody.velocity = Vector3.zero;
}
}
private void RotateAround()
{
if(reverseYaw == true)
{
target = Quaternion.Euler(0, yaw,0);
}
else
{
target = Quaternion.Euler(0, -yaw,0);
}
transform.rotation = Quaternion.Slerp(camera.transform.rotation, target, Time.time *rotationSpeed);
}
This occurs because Rigidbody.AddForce takes a world space vector, but you are giving it a local space vector. Use Transform.TransformDirection to convert your vector from local space to world space.
Vector3 force = transform.TransformDirection(0, 0, pitch);
camera.rigidbody.AddForce(force);