I'm creating a 2D Top Down game for practice and I need a little bit of help. For context, it's a 2D Top Down Shooter game, where you can move and shoot enemies. The enemies have a basic radius system where if the player gets within the radius, it'll approach the player.
Now I'm making a game mechanic where the player can hide in a cardboard box, the player can press 'E' and he'll suddenly become a cardboard box, where if the player is in the cardboard box, the enemy doesn't detect him even if the player's within the radius. Yes, just like in Metal Gear. Now I've created the prefabs and everything and functionality-wise, it works perfectly. If you press 'E' the enemy cannot detect you.
Now the small problem is that the cardboard box didn't appear, so it's just the player disappearing entirely. I do not know what caused this problem.
For context, these are my scripts. Feel free to read them, or not :)
PlayerController:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float moveSpeed;
public GameObject bulletPrefab;
public GameObject player;
private Rigidbody2D rb2d;
private Vector2 moveDirection;
[SerializeField] private Camera cam;
[SerializeField] private GameObject gunPoint;
public bool isHiding = false;
[SerializeField] private GameObject cardboardBox;
[SerializeField] private GameObject gunSprite;
// Start is called before the first frame update
void Start()
{
rb2d = GetComponent<Rigidbody2D>();
cardboardBox.SetActive(false); // Hide the cardboard box when the game starts
gunSprite.SetActive(true); // Show the gun sprite when the game starts
}
// Update is called once per frame
void Update()
{
CheckCursor();
ProcessInputs();
// Make the camera follow the player
cam.transform.position = new Vector3(player.transform.position.x, player.transform.position.y, cam.transform.position.z);
// Check if player pressed the "E" key to toggle the cardboard box
if (Input.GetKeyDown(KeyCode.E))
{
isHiding = !isHiding; // Toggle the isHiding variable
cardboardBox.SetActive(isHiding); // Show/hide the cardboard box accordingly
// If player is hiding, stop player movement
if (isHiding)
{
moveDirection = Vector2.zero;
player.GetComponent<SpriteRenderer>().enabled = false;
cardboardBox.GetComponent<SpriteRenderer>().enabled = true;
gunSprite.SetActive(false); // Hide the gun sprite when the player is hiding
}
else
{
player.GetComponent<SpriteRenderer>().enabled = true;
cardboardBox.GetComponent<SpriteRenderer>().enabled = false;
gunSprite.SetActive(true); // Show the gun sprite when the player is not hiding
}
}
}
private void FixedUpdate()
{
if (!isHiding) // Only allow player to move if they are not hiding in the cardboard box
{
Movement();
}
}
private void CheckCursor()
{
Vector3 mousePos = cam.ScreenToWorldPoint(Input.mousePosition);
Vector3 characterPos = transform.position;
if (mousePos.x > characterPos.x)
{
this.transform.rotation = new Quaternion(0, 0, 0, 0);
}
else if (mousePos.x < characterPos.x)
{
this.transform.rotation = new Quaternion(0, 180, 0, 0);
}
}
private void Movement()
{
// TODO : Implementasi movement player
rb2d.velocity = new Vector2(moveDirection.x * moveSpeed, moveDirection.y * moveSpeed);
}
private void ProcessInputs()
{
float moveX = Input.GetAxisRaw("Horizontal");
float moveY = Input.GetAxisRaw("Vertical");
moveDirection = new Vector2(moveX, moveY);
if (Input.GetMouseButtonDown(0))
{
Shoot();
}
}
private void Shoot()
{
Vector3 mousePos = cam.ScreenToWorldPoint(Input.mousePosition);
Vector3 gunPointPos = gunPoint.transform.position;
Vector3 direction = (mousePos - gunPointPos).normalized;
GameObject bullet = Instantiate(bulletPrefab, gunPointPos, Quaternion.identity);
bullet.GetComponent<Bullet>().Init(direction);
}
}
EnemyController script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyController : MonoBehaviour
{
public Transform player;
public float moveSpeed = 5f;
public float detectionRadius = 5f;
public int maxHealth = 1;
private int currentHealth;
private Rigidbody2D rb2d;
private Vector2 movement;
private void Start()
{
rb2d = this.GetComponent<Rigidbody2D>();
currentHealth = maxHealth;
}
private void Update()
{
float distanceToPlayer = Vector2.Distance(transform.position, player.position);
if (player != null && distanceToPlayer <= detectionRadius && !player.GetComponent<PlayerController>().isHiding)
{
Vector3 direction = player.position - transform.position;
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
rb2d.rotation = angle;
direction.Normalize();
movement = direction;
}
else
{
movement = Vector2.zero;
}
}
void FixedUpdate()
{
moveCharacter(movement);
}
private void moveCharacter(Vector2 direction)
{
rb2d.MovePosition((Vector2)transform.position + (direction * moveSpeed * Time.deltaTime));
}
public void DestroyEnemy()
{
Destroy(gameObject);
}
}
Bullet script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
// Start is called before the first frame update
[SerializeField] private float speed;
[SerializeField] private Vector3 direction;
public void Init(Vector3 direction)
{
this.direction = direction;
this.transform.SetParent(null);
transform.rotation = Quaternion.Euler(0, 0, Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg);
}
// Update is called once per frame
void Update()
{
this.transform.position += transform.right * speed * Time.deltaTime;
}
// TODO : Implementasi behaviour bullet jika mengenai wall atau enemy
private void OnTriggerEnter2D(Collider2D other)
{
switch(other.gameObject.tag)
{
case "Wall":
Destroy(gameObject);
break;
case "Enemy":
Destroy(gameObject);
other.gameObject.GetComponent<EnemyController>().DestroyEnemy();
break;
}
}
}
I've tried tinkering my scripts, I've tried checking if there are any missing components in the cardboard box game object but to no avail. Although I might be wrong on the Unity part since I'm fairly certain that the script isn't the problem here, again might be wrong.
I appreciate all the help I can get, thank you for reading until here
Related
When I press my jump key, the player doesn't jump but the Debug message I added does print in console.
My code:
using UnityEngine;
public class PlayerController : MonoBehaviour
{
// Start is called before the first frame update
private Transform transform;
private Rigidbody2D rb;
private bool onground = false;
public float speed;
public float momentum;
public float jumpForce;
void Start()
{
rb = gameObject.GetComponent<Rigidbody2D>();
transform = rb.transform;
}
// Update is called once per frame
void Update()
{
}
private void FixedUpdate()
{
float moveHorizontal = Input.GetAxis("Horizontal");
Vector3 movement = new Vector3(moveHorizontal, 0, 0);
transform.position += movement * Time.deltaTime * speed;
if (Input.GetButtonDown("Jump") && onground)
{
Jump(jumpForce);
}
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.collider.tag == "Floor")
{
onground = true;
Debug.Log("Player Is On Ground!");
}
}
private void OnCollisionExit2D(Collision2D collision)
{
if (collision.collider.tag == "Floor")
{
onground = false;
Debug.Log("Player Is Not On The Ground!");
}
}
private void Jump(float force)
{
rb.velocity = Vector2.up * force * Time.deltaTime;
Debug.Log("Player Has Jumped!");
}
}
the player can move but not jump and haven't found any posts anywhere with a similar issue, I might not be looking hard enough or searching the correct thing but I just cannot find a solution to my problem.
First of all, you move the player by transform component but trying to jump by physics (rigidbody), it isn't a good idea and I recommend you to work only with rigidbody in this case. Also the multiply jump force by Time.deltaTime doesn't have a sense because you call the method from FixedUpdate(), I assume that the power of jump is too week to see the result so try to remove Time.deltaTime and increase the jumpForce value.
I'm using Unity to make my character jump from a moving platform where it goes up & down infinitely. The problem I'm facing is when the moving platform goes up, the jump is working perfectly but when the platform is going down, my character can't jump most often & I can see the platform is "vibrating" a bit which is weird.
Here are my codes:
Moving Platform Script [NB - Rigidbody2D is set to Kinematic]
public class Moveground : MonoBehaviour
{
[SerializeField] private Transform posTop, posBot;
private float maxTop = -0.5f;
private float maxBot = -5.0f;
[SerializeField] private float speed;
[SerializeField] private Transform startPos;
private Vector2 nextPos;
private void Start()
{
nextPos = startPos.position;
}
private void FixedUpdate()
{
if (transform.position == posTop.position)
{
nextPos = posBot.position;
}
if (transform.position == posBot.position)
{
nextPos = posTop.position;
}
transform.position = Vector2.MoveTowards(transform.position, nextPos, speed*Time.deltaTime);
}
}
PlayerController.cs (Only Jump part)
[SerializeField] private LayerMask ground;
private Collider2D coll;
private void Start()
{
coll = GetComponent<Collider2D>();
}
private void Update()
{
InputManager();
}
private void InputManager()
{
if (Input.GetButtonDown("Jump") && coll.IsTouchingLayers(ground)) // Moving Platform's layer is also "ground"
{
Jump();
}
}
private void Jump() {
rb.velocity = new Vector2(rb.velocity.x, jumpforce); // jumpforce is a float number
}
How can I resolve this issue? I'm new to Unity.
Instead of "IsTouchingLayers" try something like this in the PlayerController class:
public bool IsGrounded()
{
return Physics2D.Raycast(transform.position, Vector3.down, 0.1f, ground);
}
and play around with the distance argument, which is the 0.1f one.
If your player transform is not at the bottom of the player, you can also put in something like this instead of 0.1f:
coll.bounds.extents.y + 0.1f
I am developing a basic game on Unity to improve myself. It's a basic endless runner platform game.
If you right click when the player is on the ground, it jumps; if it's not on the ground, it falls faster.
But I couldn't figure out how to make a player die while falling when it couldn't catch the platform. Could you please check my code? I am trying to find an "if" command to make it happen.
using JetBrains.Annotations;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class PlayerControls : MonoBehaviour
{
public Rigidbody2D rb;
public Transform groundCheck;
public float groundCheckRadius;
public LayerMask whatIsGround;
private bool onGround;
float CurrentFallTime;
public float MaxFallTime = 7;
bool PlayerIsFalling;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
void Update()
{
rb.velocity = new Vector2(5, rb.velocity.y);
onGround = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, whatIsGround);
CurrentFallTime += Time.deltaTime;
if (Input.GetMouseButtonDown(0) && onGround)
{
rb.velocity = new Vector2(rb.velocity.x, 12);
}
if (Input.GetMouseButtonDown(0) && !onGround)
{
rb.velocity = new Vector2(rb.velocity.x, -10);
}
// I want it to die and go to game over screen when it exceeds the CurrentFallTime
if ()
{
if (CurrentFallTime >= MaxFallTime)
{
SceneManager.LoadScene("GameOver");
}
}
}
}
EDIT: It solved! I simpy added "if(onGround)" and reset the CurrentFallTime. Here is the new code:
using JetBrains.Annotations;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class PlayerControls : MonoBehaviour
{
public Rigidbody2D rb;
public Transform groundCheck;
public float groundCheckRadius;
public LayerMask whatIsGround;
private bool onGround;
float CurrentFallTime;
public float MaxFallTime = 7;
bool PlayerIsFalling;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
void Update()
{
rb.velocity = new Vector2(5, rb.velocity.y);
onGround = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, whatIsGround);
CurrentFallTime += Time.deltaTime;
if (onGround)
{
CurrentFallTime = 0f;
}
if (Input.GetMouseButtonDown(0) && onGround)
{
rb.velocity = new Vector2(rb.velocity.x, 12);
}
if (Input.GetMouseButtonDown(0) && !onGround)
{
rb.velocity = new Vector2(rb.velocity.x, -10);
}
if (CurrentFallTime >= MaxFallTime)
{
SceneManager.LoadScene("GameOver");
}
}
}
This is something that I just thought of now, so I'm not sure how well it will work, but you can create a 1-sided plane collider and position it to follow the x- and y-coordinate of the player, but stay slightly lower than the height of the ground, e.g. 1unit. Then check when the player collides with the plane, if it does then you know that the player has fallen.
So, create an empty GameObject and add the collider, no need for any mesh properties and set the collider trigger to true. Then in player controls add something like in update.
colliderGo.transform.location = new Vector3(transform.x, groundHeight - 1, transform.z)
Also in the player controller function
function onTrigger(Collider col) {
if (col.tag == "fallDetector") {
Debug.Log("What a cruel world")
playHasFallen = true;
}
}
Something like this should work.
I have made a very simple gun script, currently the bullet transform in the same direction as the GameObject i have set as the bullet spawn position. but i want the bullet to transform towards the center of the camera, i have a couple of different ideas. The 1st one is shooting a raycast when the raycast hit something transform the bullet form bulletpos to raycasthit position. But i dont quite know how to do this, can anyone help me?
Here is my script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Gun : MonoBehaviour {
public Transform bulletCapTransform;
public GameObject bulletCap;
public float ammo;
public float magAmmo;
public GameObject shootEffect;
public Transform bulletTransform;
public GameObject bullet;
public float bulletForce;
public GameObject crossHair;
public float fireRate = 0.3333f;
private float timeStamp;
Animator anim;
// Use this for initialization
void Start ()
{
anim = gameObject.GetComponent<Animator>();
}
// Update is called once per frame
void Update ()
{
Shoot();
Aim();
}
public void OnGUI()
{
GUI.Box(new Rect(10, 10, 50, 25), magAmmo + " / " + ammo);
}
public void Shoot()
{
if(Time.time >= timeStamp && Input.GetButton("Fire1") && magAmmo > 0)
{
GameObject bulletCapInstance;
bulletCapInstance = Instantiate(bulletCap, bulletCapTransform.transform.position, bulletCapTransform.rotation) as GameObject;
bulletCapInstance.GetComponent<Rigidbody>().AddForce(bulletCapTransform.right *10000);
GameObject bulletInstance;
bulletInstance = Instantiate(bullet, bulletTransform) as GameObject;
bulletInstance.GetComponent<Rigidbody>().AddForce(bulletTransform.forward * bulletForce);
Instantiate(shootEffect, bulletTransform);
timeStamp = Time.time + fireRate;
magAmmo = magAmmo -1;
}
if(Input.GetKeyDown(KeyCode.R))
{
//This is just for testing
magAmmo = magAmmo + 10;
}
}
void Aim()
{
if(Input.GetButton("Fire2"))
{
anim.SetBool("Aiming", true);
crossHair.SetActive(false);
}
else
{
anim.SetBool("Aiming", false);
crossHair.SetActive(true);
}
}
}
So i think you want to fire a projectile from a "gun" object towards whatever is at the centre of your screen (regardless of central objects distance)
This script is working for me and shoots dead into the centre of the view.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Gun : MonoBehaviour
{
public Transform bulletCapTransform;
public GameObject bulletCap;
public float ammo;
public float magAmmo;
public GameObject shootEffect;
public Transform bulletTransform;
public GameObject bullet;
public float bulletForce;
public GameObject crossHair;
public float fireRate = 0.3333f;
private float timeStamp;
Animator anim;
// Use this for initialization
void Start()
{
anim = gameObject.GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
Shoot();
Aim();
}
public void OnGUI()
{
GUI.Box(new Rect(10, 10, 50, 25), magAmmo + " / " + ammo);
}
public void Shoot()
{
if (Time.time >= timeStamp && Input.GetButton("Fire1") && magAmmo > 0)
{
Debug.Log("shoot");
GameObject bulletCapInstance;
bulletCapInstance = Instantiate(bulletCap, bulletCapTransform.transform.position, bulletCapTransform.rotation) as GameObject;
bulletCapInstance.GetComponent<Rigidbody>().AddForce(bulletCapTransform.right * 10000);
//This will send a raycast straight forward from your camera centre.
Ray ray = Camera.main.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0));
RaycastHit hit;
//check for a hit
if (Physics.Raycast(ray, out hit))
{
// take the point of collision (make sure all objects have a collider)
Vector3 colisionPoint = hit.point;
//Create a vector for the path of the bullet from the 'gun' to the target
Vector3 bulletVector = colisionPoint - bullet.transform.position;
GameObject bulletInstance = Instantiate(bullet, bulletTransform) as GameObject;
//See it on it's way
bulletInstance.GetComponent<Rigidbody>().AddForce(bulletVector * bulletForce);
}
Instantiate(shootEffect, bulletTransform);
timeStamp = Time.time + fireRate;
magAmmo = magAmmo - 1;
}
if (Input.GetKeyDown(KeyCode.R))
{
//This is just for testing
magAmmo = magAmmo + 10;
}
}
void Aim()
{
if (Input.GetButton("Fire2"))
{
anim.SetBool("Aiming", true);
crossHair.SetActive(false);
}
else
{
anim.SetBool("Aiming", false);
crossHair.SetActive(true);
}
}
}
The crucial point to remember is this:
Camera.main.ViewportPointToRay(0.5, 0.5, 0);
Will shoot a raycast dead ahead from the centre of your screen.
It's worth really getting to know raycasting and it's ins and outs. it seems daunting at first but its so useful once you've got it down and it's pretty intuitive. There are a lot of good youtube tutorials.
Hope your game turns out good!
New to making games in Unity and I've tried to use every way possible to find the answer for this.
How would I add a touch screen function to this C# code in unity to make the player move left and right?
My code
using UnityEngine;
using System.Collections;
public class PlayerController : MonoBehaviour
{
private Rigidbody2D rigi;
private Animator anim;
[HideInInspector]
public bool isFacingRight = true;
public float maxSpeed = 7.0f;
public Transform groundCheck;
public LayerMask groundLayers;
private float groundCheckRadius = 0.2f;
private void Awake()
{
rigi = GetComponent<Rigidbody2D>();
anim = this.GetComponent<Animator> ();
}
void Start()
{
}
void Update()
{
}
void FixedUpdate()
{
try
{
float move = Input.GetAxis("Horizontal");
rigi.GetComponent<Rigidbody2D>().velocity = new Vector2
(move * maxSpeed, GetComponent<Rigidbody2D>().velocity.y);
this.anim.SetFloat("Speed",Mathf.Abs(move));
if((move > 0.0f && isFacingRight == false) ||
(move < 0.0f && isFacingRight == true))
{
Flip ();
}
}
catch(UnityException error)
{
Debug.LogError(error.ToString());
}
}
void Flip()
{
isFacingRight = !isFacingRight;
Vector3 playerScale = transform.localScale;
playerScale.x = playerScale.x * -1;
transform.localScale = playerScale;
}
}
You need to use the Input.touches to detect the screen touch.
Maybe in this case you should detect if the player is pressing the right/left side of the screen and moving it accordingly. You can do that by comparing the touch position, something like input.touches[0].position.x < Screen.width/2 to move right for example.
https://docs.unity3d.com/ScriptReference/Input-touches.html
Just a piece of advice, do not use GetComponent inside the update method. In this case you don't actually need it because you already have the references on the awake method.