I'm making my own avatar builder in Unity and I'm stuck on a few key bits I need to implement.
Right now I have taken the avatar that Unity provide with its Mechanim tutorial and I've gave the hat a tag and have instantiated an object at that location. This point is simply an empty game object attached as a child to the head of the model. However I'm having issues making the newly spawned object move and stay with the head as the animation plays. When the avatar moves, the hat just stays in one static position.
How can I make it so that the hat stays with the players head and moves and rotates as the animation is rotating?
My code is really simple as I've no prior experience trying do what I'm doing so even if someone could point me in the right direction on how to build an avatar creator in Unity, I'd appreciate it.
My code as it stands:
public GameObject equipItem;
public GameObject hat;
// Use this for initialization
void Start ()
{
hat = GameObject.FindGameObjectWithTag("Hat");
}
// Update is called once per frame
void Update () {
}
void OnGUI()
{
if(GUI.Button(new Rect(0,0, 100, 50), "Equip Item"))
{
SpawnWeapon();
}
}
void SpawnWeapon()
{
Instantiate(equipItem, hat.transform.position, hat.transform.rotation);
}
What you are missing is making the new object a child to the object you want it to follow. This can be done in the transform of the new object
void SpawnWeapon()
{
GameObject newObject = Instantiate(equipItem, hat.transform.position, hat.transform.rotation) as GameObject;
newObject.transform.parent = hat.transform;
}
this is the same a dragging the new object onto the other object in the inspectors hierarchy window and thus causing it to inherit all transformations made to the parent
Related
I'm trying to make a script that has an enemy chase the player only if the enemy is viewable by the player camera and the player hits the space key. I've been trying to use render.isVisible but run in to two MAJOR problems:
isVisible is enabled even if the enemy is visible in the scene view, making testing impossible.
isVisible works through walls, so if the player is looking at a wall and the enemy is behind it, it still registers as isVisible.
Please help I'm losing my mind. Thank you!
public NavMeshAgent enemy;
public Transform player;
Renderer m_Renderer;
private void Start()
{
m_Renderer = GetComponent<Renderer>();
}
private void OnBecomeInvisible()
{
enabled = false;
}
void OnBecameVisible()
{
enabled = true;
if (Input.GetKey(KeyCode.Space) && m_Renderer.isVisible)
{
Debug.Log("is visible");
enemy.SetDestination(player.position);
}
}
private void Update()
{
OnBecameVisible();
}
I'm honestly not sure what to try, thank you so much for any help!
IsVisible is really not designed for that usage. It just means object is being rendered by any camera. See the documentation here: https://docs.unity3d.com/ScriptReference/Renderer-isVisible.html
To determine whether something is actually visible from one entity by another, you typically have to do a frustum check followed by one or more raycasts to determine whether the target is blocked.
I'm trying to move my player using RigidBody2D.AddForce() method but whenever and i apply force to player on any direction then player moves for sometime then immediately stuck at random locations on level (Tile) and doesn't move ahead until opposite direction is pressed.
I wanted to move player normally without immediately making velocity = 0 like experience. It should follow slow decrease in acceleration as per force rule. I have checked my player movement on normal rigidbody without using Tilemap tiles. It's working fine but player stuck when using Tilemap tile level.
I'm calling methods using Pointer Down and Pointer Up event system for my 100px x 100px sized sprites as shown in image.
My Code:
public class PlayerScript : MonoBehaviour
{
Rigidbody2D playerRigidBody;
float speed=15f;
float forceX,forceY;
float maxVeloX,maxVeloY;
bool isMoveLeft,isMoveRight,isMoveUp;
void Start()
{
playerRigidBody=GetComponent<Rigidbody2D>();
isMoveLeft=isMoveRight=isMoveUp=false;
}
void Update()
{
forceX=forceY=0f;
maxVeloX=Mathf.Abs(playerRigidBody.velocity.x);
maxVeloY=Mathf.Abs(playerRigidBody.velocity.y);
if(isMoveRight) {
if(maxVeloX<6){
forceX= speed;
transform.localScale=new Vector3(1,1,1); // to face player right direction
}
}else if(isMoveLeft ){
if(maxVeloX<6){
forceX= -speed;
transform.localScale=new Vector3(-1,1,1); // to face left direction
}
}
else if(isMoveUp )
forceY=25f;
playerRigidBody.AddForce(new Vector2(forceX,forceY));
}
public void MoveLeftStart(){ // button left press
isMoveLeft=true;
}
public void MoveLeftEnd(){ // button left release
isMoveLeft=false;
}
public void MoveRightStart(){
isMoveRight=true;
}
public void MoveRightEnd(){
isMoveRight=false;
}
public void MoveUpStart(){
isMoveUp=true;
}
public void MoveUpEnd(){
isMoveUp=false;
}
}
My Tilemap level:
If understand right:
Your problem is caused by the fact that you are using a tilemap system made of squares colliders. And your Rigidbody is always pushed to the ground due to gravity. So everytime you collide with a corner of these colliders your character is stuck.
I suppose you are using one object to store your whole tilemap.\
If it's the case:
Go to the object your tilemap sit on.
Add component, Composite Collider 2D
On your Tilemap Collider 2D check "Used by composite"
Still in the object that contains your Tilemap:
Go on the rigidbody and set it to static
The composite collider will remove all those separate squares and regroup them.
It will remove all those little spikes.
And now (i hope) your problem is gone...
I am working on a project using Unity2D, the goal is to be able to reference other main scripts to gain information from. In this specific case, I need to detect if the mouse pointer is touching a collider, however, from a separate script.
Usually, I would be able to create a boolean, and on mouse over set it to true, on mouse exit set it to false, like this:
bool isHovered;
void OnMouseEnter() {
isHovered = true;
}
void OnMouseExit() {
isHovered = false;
}
However, in the script, instead of doing this for each individual script, I would like to reference another script, like this:
public GameManager g;
void Update() {
if (g.IsTouchingMouse(gameObject)) { //Code }
}
But there's multiple problems with this. In my game manager class, I would need something like this
public bool IsTouchingMouse(gameObject g) { return value }
Which there is multiple issues with this, because I don't have a way to register the OnMouseEnter and OnMouseExit events for those objects on another script, and I don't have a way to store the values for every single gameObject to ensure this will work for every object without having to manually modify this script.
I'm looking for two things, #1, how can I detect mouseovers on objects from scripts who's parents are not that gameObject, two, are there any ideas on how I would go about creating a function to return this variable instantly?
Somewhat annoying, but I figured out a solution a few minutes after posting. So I will share it here.
public bool IsTouchingMouse(GameObject g)
{
Vector2 point = Camera.main.ScreenToWorldPoint(Input.mousePosition);
return g.GetComponent<Collider2D>().OverlapPoint(point);
}
What this code is basically doing, is making a function that takes a gameObject as an input, creates a vector2 based on the position of the mouse cursor in world space, and then returns weather or not the 2D collider that the object contains is actually touching this imaginary point, the variable "point" should be interchangable with any 2D world space location. I was pretty much overcomplicating the entire issue.
Find two resources you like and import them into Unity's Assets and set their Texture Type to Cursor
Create a new script and mount it to an empty object.
Open the script, create three public variables of type Texture2D, return to Unity and drag your favorite pointer map to the variable window.
To set the object label, we judge which pointer to change by customizing the label; so first set the label for the object. For example, the ground, I added the Ground tag to it, the wall added the Wall tag; the column added the Cylinder tag.
Write a method to change the mouse pointer, where the main API for changing the pointer is Cursor.SetCursor()
void setCursorTexture()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);//Define the ray pointed by the mouse in the game window
RaycastHit hitInfo; //Information of ray collision
if (Physics.Raycast(ray, out hitInfo))//Determine whether to hit the object
{
// switch pointer
switch (hitInfo.collider.gameObject.tag)
{
case "Ground":
Cursor.SetCursor(groundCr, new Vector2(16, 16), CursorMode.Auto);
break;
case "Wall":
Cursor.SetCursor(wallCr, new Vector2(16, 16), CursorMode.Auto);
break;
case "Cylinder":
Cursor.SetCursor(CylinderCr, new Vector2(16, 16), CursorMode.Auto);
break;
default:
Cursor.SetCursor(null,Vector2.zero,CursorMode.Auto);
break;
}
}
}
Implement this method in the Update() method called every frame.
END (you can go to run the program) Thank you and hope to help you
This method works without exception. To solve the problem try the following method:
public Collider2D collider; // target Collider
void Update()
{
var mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
if (collider.bounds.IntersectRay(mouseRay)) Debug.Log("Mouse on collider..");
}
For New Input System?
But Input.mousePosition gives a new system error in Unity. To solve this problem, call the mouse position as shown below:
var mousePos = Mouse.current.position.ReadValue();
You can also check if (new input system enabled) is active as below:
#if ENABLE_INPUT_SYSTEM
var mousePos = Mouse.current.position.ReadValue();
#else
var mousePos = Input.mousePosition;
#endif
then follow the direction of the camera ray:
var mouseRay = Camera.main.ScreenPointToRay(mousePos);
I just start to learn HTC vive app development with unity and want to interact with Object and want to get it as controller interact with it.
Try to learning form StreamVR Unity Toolkit documentation. I found a scene in sample demo where Gameobject are interacting through controller but there are so many scripts involved. I am amazed that on a cube VRTK_InteractalbeObject is attached and it is responding to controller. how can i get interacted object in htc vive.?
So, here is one of many solutions to interact with objects with controllers - I will show here the easiest one.
A. Find [CamerRig] prefab from SteamVR folder and place it in hierarchy:
B. Find Controller (right)->Model GameObject in it:
C. Create GameObject with Rigidbody and SphereCollider and place it as child of Controller (right)->Model GameObject
C.1. Be sure that this object is in same position as Model GameObject
D. Now play the game, and moving your right vive controller push some other GameObjects that have Rigidbody and any Collider.
E. To use vive controller Buttons use this script, and place it on Controller (right) GameObject.
public class VIVEController : MonoBehaviour
{
public SteamVR_TrackedObject trackedObj;
private SteamVR_Controller.Device controller;
void Start ()
{
controller = SteamVR_Controller.Input ((int)trackedObj.index);
}
void Update ()
{
if (controller.GetPressDown (Valve.VR.EVRButtonId.k_EButton_SteamVR_Trigger))
{
OnTriggerPressed ();
}
if (controller.GetPressDown (Valve.VR.EVRButtonId.k_EButton_SteamVR_Touchpad))
{
OnTouchpadPressed ();
}
}
private void OnTriggerPressed()
{
Debug.Log("OnTriggerPresse");
}
private void OnTouchpadPressed()
{
Debug.Log("OnTouchpadPressed");
}
}
F. Assign from inspector trackedObj (It is on same GameObject as this script)
G. Find script SteamVR_RenderModel and comment out in method LoadComponents
for (int i = 0; i < t.childCount; i++)
{
var child = t.GetChild(i);
child.gameObject.SetActive(false);
StripMesh(child.gameObject);
}
This is necessary, as otherwise your custom GameObject with collider that is child of controller model, will become inactive.
Resuming - it is very easy, but you need to do quite few steps.
Try playing with controllers buttons, to for instance push object only when you press trigger.
As bonus, here is small game I made with same approach:
https://www.youtube.com/watch?v=kzX7Iw6cHZ8
This is semi complicated of a question but I'll do my best to explain it:
I am making this mobile game in which you have to shoot four cubes. I'm trying to make it so when the cubes are shot by a bullet, they're destroyed and a UI text says 1/4, to 4/4 whenever a cube is shot. But it's being really weird and only counts to 1/4 even when all four cubes are shot and destroyed. I put these two scripts on the bullets (I made two separate scripts to see if that would do anything, it didn't)
And to give a better idea of what I'm talking about, here's a screenshot of the game itself.
I've been using Unity for about 6 days, so I apologize for anything I say that's noob-ish.
EDIT
So I combined the two scripts onto an empty gameobject and here's the new script:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class GameManagerScript : MonoBehaviour {
public GameObject cubes;
public Text countText;
public int cubeCount;
public Transform target;
// Use this for initialization
void Start () {
}
void OnTriggerEnter(Collider other)
{
cubes = other.gameObject;
}
// Update is called once per frame
void Update () {
cubes.transform.position = Vector3.MoveTowards(transform.position, target.position, 1f * Time.deltaTime);
if (cubes.gameObject.tag == "BULLET")
{
cubeCount = cubeCount + 1;
countText.text = cubeCount + "/4";
cubes.SetActive(false);
}
}
}
ANOTHER EDIT
I tried everything, so is there a way to detect when all the children in a parent on the Hierarchy are destroyed? Instead of counting up? This can give a better idea:
So I want to be able to detect when Cube, Cube1, Cube2, and Cube3 have all been destroyed.
The answer is pretty simple: Since every individual bullet has that script, each bullet has its own score.
For something like a score you want a single spot to store it, e.g. a script on an empty gameobject that serves as game controller. Just access that in the collision and increase the score (maybe have a look on singletons here).
You can combine those two scripts and actually it might be better to not have this on the bullet, but on the target because there are probably less of them which will save you some performance. (And it does more sense from a logical point of view.)
Edit:
I assume you create the bullets using Instantiate with a prefab. A prefab (= blueprint) is not actually in the game (only objects that are in the scene/hierarchy are in the game). Every use of Instantiate will create a new instance of that prefab with it's own version of components. A singleton is a thing that can only exist once, but also and that is why I mention it here, you can access it without something like Find. It is some sort of static. And an empty gameobject is just an object without visuals. You can easily create one in unity (rightclick > create empty). They are typically used as container and scriptholders.
Edit:
What you want is:
An empty gameobject with a script which holds the score.
A script that detects the collision using OnTriggerEnter and this script will either be on the bullets or on the targets.
Now, this is just a very quick example and can be optimized, but I hope this will give you an idea.
The script for the score, to be placed on an empty gameobject:
public class ScoreManager : MonoBehaviour
{
public Text scoreText; // the text object that displays the score, populate e.g. via inspector
private int score;
public void IncrementScore()
{
score++;
scoreText.text = score.ToString();
}
}
The collision script as bullet version:
public class Bullet : MonoBehaviour
{
private ScoreManager scoreManager;
private void Start()
{
scoreManager = GameObject.FindWithTag("GameManager").GetComponent<ScoreManager>(); // give the score manager empty gameobject that tag
}
private void OnTriggerEnter(Collider other)
{
if(other.CompareTag("Target") == true)
{
// update score
scoreManager.IncrementScore();
// handle target, in this example it's just destroyed
Destroy(other.gameObject);
}
}
}