I'm making a 2D game with two sides, left and right, so the player can only move to the left or right or jump. I made an AI as the enemy. The AI is working fine. He can go to the player to kill him.
The problem is the enemy can't rotate or face the player when he goes to kill him. I want the AI to look at the player. When the player is to the left of the enemy, the enemy should rotate to the left to look at the player. I searched many websites and I didn't get any correct solution. This is my enemy script:
public class enemy : MonoBehaviour
{
public float speed;
private Animator animvar;
private Transform target;
public GameObject effect;
public float distance;
private bool movingRight = true;
public Transform groundedDetection;
public float moveInput;
public bool facingRight = true;
void Start()
{
animvar = GetComponent<Animator>();
target = GameObject.FindGameObjectWithTag("Player").transform;
}
// Update is called once per frame
void Update()
{
if (Vector3.Distance(target.position, transform.position) < 20)
{
transform.position = Vector2.MoveTowards(transform.position, target.position, speed * Time.deltaTime);
}
else
{
transform.Translate(Vector2.right * speed * Time.deltaTime);
}
RaycastHit2D groundInfo = Physics2D.Raycast(groundedDetection.position, Vector2.down, distance);
}
void OnCollisionEnter2D(Collision2D col)
{
if (col.gameObject.tag.Equals("danger"))
{
Instantiate(effect, transform.position, Quaternion.identity);
Destroy(gameObject);
}
if (col.gameObject.tag.Equals("Player"))
{
Instantiate(effect, transform.position, Quaternion.identity);
Destroy(gameObject);
}
}
}
The game is 2D, left, right, with jump using Unity3D.
You need a function that would flip your sprite, you can do that by changing the scale of the transform, and keep a boolean to check where it's facing
bool facingRight;, so something like this
void Flip(){
Vector3 scale = transform.localScale;
scale.x *= -1;
transform.localScale = scale;
facingRight = !facingRight;
}
and in your Update check if it needs to be flipped or not
if (Vector3.Distance(target.position,transform.position)<20)
{
transform.position=Vector2.MoveTowards(transform.position, target.position,speed*Time.deltaTime);
if(target.position.x > transform.position.x && !facingRight) //if the target is to the right of enemy and the enemy is not facing right
Flip();
if(target.position.x < transform.position.x && facingRight)
Flip();
}
Its simple enough, just get the Player x position and compare to Enemy's x position, then flip the enemy sprite accordingly
This is my Update() method in my Enemy script. This handles enemy movement and changing direction the sprite is facing:
if (moveRight )
{
transform.Translate(2 * Time.deltaTime * moveSpeed, 0, 0);
transform.localScale = new Vector2(6, 6); //6,6 is just a size that suits my sprite
}
else if (!moveRight)
{
transform.Translate(-2 * Time.deltaTime * moveSpeed, 0, 0);
transform.localScale = new Vector2(-6, 6);
}
This is my enemy Attack() method , I compare the Player X position to Enemy X position. If Player X is less( to the left of the Enemy), I flip the Enemy sprite to negative
if (transform.position.x > Player.position.x)
{
transform.localScale = new Vector2(-6, 6);
}
else if (transform.position.x < Player.position.x)
{
transform.localScale = new Vector2(6, 6);
}
Related
I have a cloud which has a polygon collider 2d attached. Also, I have a player that has a box collider 2d attached. When the player lands on the cloud, at some point during the movement, something is stopping him. He is animating but he does not move.
Below is the image of my colliders:
When I start running the game, he moves left and right. So I figured it is not a code issue. At a point, he is stuck at the above position and he cannot move right but he can move left. I guess the polygon collider is stopping him from free movement. When I go back, he is walking and when the reaches the above position, he cannot move forward.
Is there any workaround for this?
Below is my code:
public class Player : MonoBehaviour
{
public float speed = 7f;
public float maxVelocity = 8f;
private Rigidbody2D rb;
private Animator anim;
void Awake()
{
rb = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void FixedUpdate()
{
MovePlayerUsingKeyboard();
}
public void MovePlayerUsingKeyboard()
{
float forceX = 0f;
float velocity = Mathf.Abs(rb.velocity.x);
Debug.Log("Player Velocity : " + velocity);
float direction = Input.GetAxis("Horizontal");
if (direction < 0)
{
if (maxVelocity > velocity)
{
anim.SetBool("Walk", true);
forceX = -speed;
}
//Changing the direction the player faces
Vector3 temp = transform.localScale;
temp.x = -1.3f;
transform.localScale = temp;
}
else if (direction > 0)
{
if (maxVelocity > velocity)
{
anim.SetBool("Walk", true);
forceX = speed;
}
Vector3 temp = transform.localScale;
temp.x = 1.3f;
transform.localScale = temp;
}
else
{
anim.SetBool("Walk", false);
}
rb.AddForce(new Vector2(forceX, 0));
}
}
I think it is because that the collider of your character is stuck at the bumpy part of the cloud's polygon collider.
A solution is to change the character's collider to semi-capsule collider or capsule collider so that the character can walk smoothly on some rough surfaces.
I have made a script for player movement in a 3D game in Unity.
I like how the movement works, but when I jump while moving, the player keeps moving in that direction at the same speed till it falls to the ground, which is the expected behavior for this script.
But I want to be able to move the player in the air slightly (not fully controllable.)
I'm imagining kinda like a minecraft like movement to be exact.
Any advice to improve this code would be greatly apprecciated.
This is my code.
using System.IO;
using UnityEngine;
public class VelocityMovement : MonoBehaviour
{
#region Variables
public float speed;
public float gravity;
public float maxVelocityChange;
public float jumpHeight;
public float raycastDistance;
public Rigidbody rb;
#endregion
private void Awake()
{
//gets rigidbody, freezes rotation of the rigidbody, disables unity's built in gravity system on rigidbody.
rb = GetComponent<Rigidbody>();
rb.freezeRotation = true;
rb.useGravity = false;
}
private void Update()
{
//Jump system
if(Grounded())
{
if (Input.GetKeyDown(KeyCode.Space))
{
rb.velocity = new Vector3(rb.velocity.x, CalculateJumpSpeed(), rb.velocity.z);
}
}
}
private void FixedUpdate()
{
//Moves the player when on the ground.
if (Grounded())
{
//Calculate how fast the player should be moving.
Vector3 targetVelocity = new Vector3(playerInputs.hAxis, 0, playerInputs.vAxis);
targetVelocity = transform.TransformDirection(targetVelocity);
targetVelocity *= speed ;
//Calculate what the velocity change should be
Vector3 velocity = rb.velocity;
Vector3 velocityChange = (targetVelocity - velocity);
velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
velocityChange.z = Mathf.Clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange);
velocityChange.y = 0f;
//applies a force equal to the needed velocity change
rb.AddForce(velocityChange, ForceMode.VelocityChange);
}
//Adds gravity to the rigidbody
rb.AddForce(new Vector3(0, -gravity * rb.mass, 0));
}
//Checks if player is on the ground
private bool Grounded()
{
return Physics.Raycast(transform.position, Vector3.down, raycastDistance);
}
//calculates how high the player should be jumping
private float CalculateJumpSpeed()
{
return Mathf.Sqrt(2 * jumpHeight * gravity);
}
}
private void FixedUpdate()
{
//check how big the movement is. Swap SomeSmallValue with a float like 0.1f
float actualSpeed;
Vector3 velocity;
if(Grounded())
{
actualSpeed = speed;
//HERE IT IS NOT, THIS DOESN'T MATTER
velocity = rb.velocity
}
else{
actualSpeed = speed * SomeSmallValue;
//WITH THIS rb KEEPS THE SPEED IF ANY BUTTON IS PRESSED
velocity = 0;
}
//Moves the player ALWAYS.
//Calculate how fast the player should be moving.
Vector3 targetVelocity = new Vector3(playerInputs.hAxis, 0, playerInputs.vAxis);
targetVelocity = transform.TransformDirection(targetVelocity);
//if Grounded == true the movement is exactly the same than before, because actualSpeed = speed.
//If Grounded == false, the movement is so light
targetVelocity *= actualSpeed;
//Calculate what the velocity change should be
//I'VE PLACED THIS UP IN ORDER TO CALL Grounded() ONLY ONE TIME
//Vector3 velocity = rb.velocity;
Vector3 velocityChange = (targetVelocity - velocity);
velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
velocityChange.z = Mathf.Clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange);
velocityChange.y = 0f;
//applies a force equal to the needed velocity change
rb.AddForce(velocityChange, ForceMode.VelocityChange);
//Adds gravity to the rigidbody
rb.AddForce(new Vector3(0, -gravity * rb.mass, 0));
}
If your code is working fine, try something like this. Just moved the grounded condition. Now the movement works also at air time. We check with that grounded bool how big the movement is.
If I understood you correctly you want to slow down what your movements do while mid air.
at least that is the case for left and right.
If I did undersand you correctly, you would make an else{} after the if(Grounded())
and go from there, may make some float variable that acts as a multiplier for you left/right control while mid air, aswell as another float variable for forward and backwards.
Inside that else you could just multiply you speed with the variables (depending on the axis) and you should get some form of slower movement there.
I hope that helped you out at least a bit.
I have a ball that have a continuous bouncing, and I want to move it left and right in the x Axis with the mouse, so it follow the mouse's X movement.
I made the script bellow, but the ball didn't move with mouse!
Ball Script:
private Vector3 pos;
public Camera cam;
public Rigidbody Ball;
public float Speed;
public static float GlobalGravity = -9.8f;
public float GravityScale = 1.0f;
bool isforce = false;
private void Start(){
Ball = GetComponent<Rigidbody>();
Ball.useGravity = false;
}
private void FixedUpdate(){
Vector3 gravity = GlobalGravity * GravityScale * Vector3.up;
Ball.AddForce(gravity, ForceMode.Acceleration);
}
void force (){
isforce = false;
Ball.AddForce(Vector3.up * Speed, ForceMode.Impulse);
}
private void Update(){
if (isforce == true){
force();
}
if (Input.GetMouseButton(1)){
Vector3 mousePos = Input.mousePosition;
Vector3 wantedPos = Camera.main.ScreenToWorldPoint(new Vector3(mousePos.x, transform.position.y, 10));
transform.position = wantedPos;
}
}
private void OnCollisionEnter(Collision collision){
isforce = true;
}
try this and let me know what happens. yours was set to right click, but i changed this one to left click, other than that i just sat the balls x to the raw x of the mouse input.
private void Update(){
if (isforce == true){
force();
}
if (Input.GetMouseButton(0)){
Vector3 mousePos = Input.mousePosition;
Vector3 wantedPos = transform.position;
wantedPos.x=Input.mousePosition.x;
transform.position = wantedPos;
}
}
When you use transform.position, the Unity Physics will no apply to the rigidBody. Find your mouse position relative to the ball and add Force in the X direction accordingly.
You have a couple of options depending on what it is you want.
Also as #Hamed answered, when using physics you don't want to update the transform directly but add force using the Rigidbody.
Force Constant relative to where the Mouse is
if (Input.GetMouseButton(0))
{
Vector2 force = Vector2.zero;
//Get the Balls current screenX position
float ballX = Camera.WorldToScreenPoint(Ball.transform.position).x;
//Check if Click was Left or Right of the Ball
if (ballX > Input.mousePosition.x)
{
//Click was Left of the Ball
force = new Vector2(-1f, 0f);
}
else if (ballX < Input.mousePosition.x)
{
//Click was Right of the Ball
force = new Vector2(1f, 0f);
}
//Adjust force amount to your suiting
Ball.Addforce(force * Time.deltaTime);
}
Force relative to the mouse movement
if (Input.GetMouseButton(0))
{
Vector2 force = Vector2.zero;
float mouseDelta = Input.GetAxis("Mouse X");
//Check if the Mouse is going Left or Right
if (mouseDelta < 0f)
{
//Click was Left of the Ball
force = new Vector2(-1f, 0f);
}
else if (mouseDelta > 0f)
{
//Click was Right of the Ball
force = new Vector2(1f, 0f);
}
// Update force relative to mouse movement
force = Mathf.Abs(mouseDelta) * force;
//Adjust force amount to your suiting
Ball.Addforce(force * Time.deltaTime)
}
Hastily written, look then write your own :)
There is a strange behavior when my spaceship fires off some missiles to destroy an enemy. Under certain circumstances, the missiles "jump" and fly away.
This seems to happen when the nearest enemy is destroyed by one missile and all others have no target any more. Then they "jump" and fly away (off the screen).
I still don't know the cause of this problem.
void Start () {
rb = this.GetComponent<Rigidbody2D>();
nearestEnemy = FindClosestTarget("EnemyShipTag");
}
Getting the closest target (enemy)
GameObject FindClosestTarget(string _target) {
enemies = GameObject.FindGameObjectsWithTag(_target);
closest = null;
distance = Mathf.Infinity;
_position = this.transform.position;
foreach (GameObject enemy in enemies) {
diff = enemy.transform.position - _position;
curDistance = diff.sqrMagnitude;
if (curDistance < distance) {
closest = enemy;
distance = curDistance;
}
}
return closest;
}
Calculate movement to nearest enemy if nearestEnemy is not null
void FixedUpdate () {
if (nearestEnemy != null) {//is enemy available?
Vector2 enemyTarget = nearestEnemy.transform.position;
Vector2 direction = (Vector2)enemyTarget - rb.position;
direction.Normalize ();
float rotateAmount = Vector3.Cross (direction, transform.up).z;
rb.angularVelocity = -rotateAmount * rotateSpeed;
float speed = 6f;
float step = speed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, nearestEnemy.transform.position, step);
} else {
//rocket shall fly straight ahead if there's no target
rb.velocity = transform.up * speed;
}
These functions are part of the EnemyControl.cs-script
void OnTriggerEnter2D (Collider2D col) {//this function will trigger when there is a collision of our game objects
//detect collision of the enemy ship with the player ship, or with a player's bullet
if ((col.tag == "PlayerShipTag") || (col.tag == "MissileUpgradeTag")) {
EnemyDestroyed ();
}
void EnemyDestroyed () {
Destroy (gameObject);//Destroy the enemy ship
dead = true;
PlayerControl.enemiesDestroyed++;
}
I'm working on a 2D game (for smartphone) which is automatically jumping, and I want to give a player movement (accelerometer) (a similar principle as doodle jump). How to make automatically jumping of 2D sprite? I tried to create an animation but it will not move using the accelerometer. So I coded script for automatically jump but it's not working. any help? (automatically jump means when player hits ground, jump again)
public float speed = 6.0F;
public float jumpSpeed = 8.0F;
public float gravity = 20.0F;
private Vector3 moveDirection = Vector3.zero;
Rigidbody2D coll;
void Start(){
coll = GetComponent<Rigidbody2D>();
}
void Update() {
if (coll.gameObject.tag == "Ground") {
moveDirection = Vector3.zero;
moveDirection.x = 1;
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= speed;
}
}
}
So can someone give me script when player hit ground, player will jump? I want to move up and to the right.
Player object should have collider2D and rigidbody2D. Ground object should have collider2D and "Ground" tag. This code must be on player object.
public int power;
void Update()
{
transform.position = new Vector3(transform.position.x + Input.acceleration.x, transform.position.y, transform.position.z);
}
void OnCollisionEnter2D(Collision2D col)
{
if (col.collider.gameObject.tag.Equals("Ground"))
{
rigidbody2D.AddForce(Vector2.up * power);
}
}
I hope it works.