I'm making a 2D game and trying to make a characters move automatically when they spawn from the door to the desk or close to the sofa then stop there. the problem is that they don't collide with anything in the background like sofa or table or desk and they keep going trying to force move and going out of the canvas. this is a GIF for the game play and script that i'm using on the characters:
What am I supposed to do?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CharacterConstantMove : MonoBehaviour
{
GameManager Game_Manager;
void Start()
{
GameObject gameController = GameObject.FindGameObjectWithTag("GameController");
Game_Manager = gameController.GetComponent<GameManager>();
}
void Update()
{
transform.Translate(Game_Manager.moveVector * Game_Manager.moveSpeed * Time.deltaTime);
}
}
GameManager.Cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
public float moveSpeed = 1.0f;
public Vector2 moveVector;
}
That's what happens when you translate the body in every frame. From an answer to this similar problem has been addressed, Transform is not a physics-based component. It's the position, rotation, and scale of the object. It doesn't interact with physics system on it's own. Rigidbody is a physics-based component that performs different kinds of physics interactions, like collisions, forces, and more.
Add a rigidbody component to your gameobject and set its velocity, it then interacts with the game physics.
private Rigidbody2D rb;
private void Awake() {
rb = GetComponent<Rigidbody2D>();
}
private void Update() {
rb.velocity = Game_Manager.moveVector * Game_Manager.moveSpeed;
}
Related
I'm trying to implement chest mechanic in my game. When a user touches to chest, chest disappears and heart shows up. When player touches the instantiated heart, it must disappear and add 1 to life value, but the script is not working.
Chest.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Chest : MonoBehaviour
{
public GameObject heart;
public GameObject _heart; //Instantiated heart.
void OnTriggerEnter2D(Collider2D col){
if (col.gameObject.tag == "Player"){
Vector3 insPos = transform.position;
_heart = Instantiate(heart,new Vector3(insPos.x,insPos.y+0.5f,insPos.z),Quaternion.identity);
_heart.AddComponent<Heart>();
_heart.GetComponent<Heart>().ls = GameObject.FindGameObjectWithTag("Player").GetComponent<LifeSystem>();
Destroy(gameObject);
}
}
}
Heart.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Heart : MonoBehaviour
{
public LifeSystem ls;
void OnTriggerEnter2D(Collider2D col){
if (col.gameObject.tag == "Player"){
SoundManager.PlaySound("CollectCoinSound");
ls.lifes += 1;
Destroy(gameObject);
}
}
}
I check the components of the instantiated heart when player touches the chest and I can see that life system reference is added and so heart script is.
Thanks for your time.
You need to meet these conditions in order for OnTriggerEnter2D to be called on the spawned Hearth:
At least one between Player and Hearth need to have a Rigidbody2D component
Both Player and Hearth need to have a collider with IsTrigger = true
Player and Hearth GameObjects need to be on two interacting layers in the collision matrix
The Hearth component needs to be either on the same GameObject with a collider or on the same GameObject with the RigidBody2D
I actually simplified rules 1 and 2 a bit to show the most common use-case: if you want to know the actual rules for collisions, you can find them here (see the matrix at the bottom).
Besides the general collision rules I would make sure your fields have the correct type in the first place and already attach the Heart component to your prefab.
Also there is no need for find .. You already know the reference to the player you are colliding with
public class Chest : MonoBehaviour
{
public Heart heartPrefab;
void OnTriggerEnter2D(Collider2D col)
{
if (col.CompareTag("Player"))
{
Instantiate(heart, transform.position + Vector3.up * 0.5f), Quaternion.identity);
Destroy(gameObject);
}
}
}
and then simply do
public class Heart : MonoBehaviour
{
private void OnTriggerEnter2D(Collider2D col)
{
if (col.TryGetComponent<LifeSystem>(out var ls))
{
SoundManager.PlaySound("CollectCoinSound");
ls.lifes += 1;
Destroy(gameObject);
}
}
}
and rather have the LifeSystem attached to your player object.
In general I would kind of expect both eventually triggered at the same time since the heart might be already triggered if spawning right where the player is
I am looking to make my first actual game called Bottomless. It seems I am having a problem with the obstacle generator script in Unity2D. I want the obstacle to generate vertically, where a player is falling down the level.
Here my script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Generator : MonoBehaviour
{
public GameObject spike;
public float maxspeed;
public float minspeed;
public float currentspeed;
void Awake()
{
currentspeed = Random.Range(maxspeed, minspeed);
spikegen();
}
void spikegen()
{
GameObject SpikeIns = Instantiate(spike, transform.position, transform.rotation);
}
void Update()
{
}
}
Seems like running this code crashes unity quickly. Does anyone have better alternative?
So, I have been considering your problem, and I think the best thing to do would be to create spawn points in your map pieces for the spikes to fit in. Then, when your player is falling, and the new map is loaded, grab the spawn points, add them to a list, choose one randomly, and then instantiate your spike there. Or get the map pieces themselves to spawn the spikes as they are loaded.
Method 1:
Create spawn points on your map piece. Create and add the following script. Place the spawn points in the list in inspector. And call function on Awake/Start.
using System.Collections;
using UnityEngine;
public class MapScript : MonoBehaviour
{
//Spike you want to instantiate
public GameObject spike;
//List for you to place spawn points in the inspector
public List<GameObject> Spawnpoints = new List<GameObject>();
public void Awake()
{
//Get a random number from 0 to our lists count
int random = Random.Range(0, Spawnpoints.Count);
//Instantiate at the random spawn point
GameObject SpikeIns = Instantiate(spike, Spawnpoints[random].transform.position, transform.rotation);
}
}
Method 2:
Similar to the example above, except the code to spawn happens in the Generator script (this is not the preferred method as we will have to access the map piece's script).
So use the code above but remove the Awake and spike GameObject, and then for your generator script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Generator : MonoBehaviour
{
public GameObject spike;
public float maxspeed;
public float minspeed;
public float currentspeed;
void Awake()
{
currentspeed = Random.Range(maxspeed, minspeed);
spikegen();
}
void Update()
{
}
void spikegen()
{
List<GameObject> Spawners = new List<GameObject>();
foreach(GameObject spawn in refernceToOtherScripts.Spawnpoints)
{
Spawners.Add(spawn);
}
int random = Random.Range(0, Spawners.Count);
GameObject SpikeIns = Instantiate(spike, Spawners[random].transform.position, transform.rotation);
}
}
Neither of these have been tested as I am on my work computer, but they should both work perfectly fine. As you have probably guessed, there are a lot of different way to go about this.
I am making a game and in the game im trying to make the enemy go towards the player when the player steps into the sight of the enemy. I cant figure out how to make the name (player) mean anything im very new at this its my second attempt on makin a game please help me im very confused im running c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
private Transform _target;
[SerializeField] private float _speed = 9;
void Awake() {
_target = FindObjectOfType(Player)().transform;
}
void update() {
transform.position = Vector3.MoveTowards(transform.position,_target.position, _speed * Time.deltaTime);
}
}
You need to use the typeof operator instead of passing the class name.
void Awake() {
_target = FindObjectOfType(typeof(Player))().transform;
}
I've been learning UNet to create a LAN multiplayer game and everything is going really well except the player damage.
The goal here is to sync the death enough that both clients realize the death has happened, and it is supposed to reload the scene, using NetworkManager.singleton.ServerChangeScene("SampleScene");
However the death only updates on one client, but a new error has appeared. When I acquire and call one of the methods from my PlayerDamage script, it returns an error saying there is no argument in the method that corresponds to my float amount constructor. Here is the code from my Gun and PlayerDamage script.
Gun:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
public class Gun : NetworkBehaviour {
public float damage = 10f;
public float range = 100f;
public Camera fpsCam;
public AudioSource pistol;
//public ParticleSystem muzzleFlash;
//[SerializeField] private ParticleSystem part;
//public float shotTime = .25f;
private void Update()
{
if (Input.GetButton("Fire1"))
{
Shoot();
pistol.Play();
}
}
void Shoot()
{
RaycastHit hit;
if (Physics.Raycast(fpsCam.transform.position, fpsCam.transform.forward, out hit, range))
{
PlayerDamage target = hit.transform.GetComponent<PlayerDamage>();
target.takeDamage();
}
}
}
PlayerDamage:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
public class PlayerDamage : NetworkBehaviour {
[SyncVar]
public float health = 50f;
[ClientRpc]
public void CmdTakeDamage(float amount)
{
Debug.Log("took damage" + amount);
}
public void takeDamage(float amount)
{
health -= amount;
CmdTakeDamage(amount);
}
public void Die()
{
NetworkManager.singleton.ServerChangeScene("SampleScene");
}
}
Thanks in advance, FerretCode
You'll need to send a message across all other clients in order for them to be updated on a certain player. In order to do that, you'll need to have some sort of a game event bus that handles the receiving and dispatching of game events throughout the network.
Say if you have three players playing your game and one of them dies, it sends a network message to the host (regardless if it's a server or a player) that a player X died. The host will now send a message to other players Y, and Z, except X that player X died and thus notifying them so that clients Y and Z will be able to kill player X on their side.
Multiplayer games are harder than it looks, and you'll need to design a system where can make every one of the clients synchronize all at the same time before doing any gameplay-related stuff.
Brand new to C# and Unity.Please be nice I've been at this all night. Every tutorial I poor through says changing an object from invisible to visible is as simple as setting the game object to on. However Unity gives me an error when I declare a game object in this script. The objective is, when the trigger is entered, several game objects called 'spawn' will become visible.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class collider : MonoBehaviour
{
public gameObject Spawn; // I get error On this line that type is expected,
//not property. It wants a Transform>
private Rigidbody rb;
void Start ()
{
rb = GetComponent<Rigidbody>();
}
void OnTriggerEnter(BoxCollider other)
{
if (other.gameObject.CompareTag("Player"))
{
Spawn.SetActive(true);
}
}
}
gameObject isn't a type, but GameObject is.
Get rid of public gameObject Spawn; and use public GameObject Spawn; to declare a GameObject property called Spawn