I have a tutorial scene where you go through the level and reach a certain door, when you collide with that, it disables a canvas at the top, and animates the door. I've searched everywhere in the Scripting Docs, but can't find the solution. What type of variable do you declare the object to animate?
I tried declaring public GameObject/Transform UIQuest and UIQuest.Animation.Play("DoorOpen"), but it comes up with the error of not having the Animation in the API for that. Am I just doing this completely wrong or is there something simple I'm missing?
Complete script:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class DoorOpen : MonoBehaviour {
public GameObject door;
public Canvas UIQuest;
void Start () {
}
void Update () {
}
void OnCollisionEnter(Collision doorCollision)
{
if (doorCollision.gameObject.name == "Door")
{
door.Animation.Play("DoorOpen");
UIQuest.enabled = false;
}
}
}
As the gameobject is only performing a simple animation you do not need anything special (such as an AnimationController), you simply need to perform a rotation of the door over time, set the pivot of the door to the edge and rotate the door along the y-axis when conditions are met (i.e. when a collision is detected).
Something like :
gameobject.transform.Rotate(0, rotationAmount * Time.DeltaTime, 0);
You will also need logic to decide when to stop the rotation (i.e. when the door is fully open) unless you want a revolving doorway. Also if the door is just a sliding door this is even easier as you perform a translate instead of a rotate.
Related
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 trying to create a simple scriptable object for my shoot ability. I have that aspect working, but as I try to set my Transform to my player, it does not update the shoot position. I am very new to C#, and this script isnt complete. I still need to add the functionality to destroy the created objects. Any help would be greatly appreciated. I suspect I need to add an update function but im am not certain how to do this.
using UnityEngine.InputSystem;
using UnityEngine.AI;
using UnityEngine;
namespace EO.ARPGInput
{
[CreateAssetMenu]
public class Shoot : Ability
{
public Transform projectileSpawnPoint;
public GameObject projectilePrefab;
public float bulletSpeed = 10;
public float bulletLife = 3;
public override void Activate(GameObject parent)
{
var projectile = Instantiate(projectilePrefab, projectileSpawnPoint.position, projectileSpawnPoint.rotation);
projectile.GetComponent<Rigidbody>().velocity = projectileSpawnPoint.forward * bulletSpeed;
Destroy(projectile, bulletLife);
void OnCollisionEnter(Collision collision)
{
Destroy(projectile);
}
}
}
}
I'm still new to Unity and coding also, so take my advice with a load of salt :P.
It may be best to have a transform on your character (say just past the barrel of the player's gun) that you can put as the projectileSpawnPoint. In your code the projectileSpawnPoint is never set. Your first line of code in the "Activate" method should be something like:
public override void Activate(GameObject parent)
{
projectileSpawnPoint = playerGunBarrelTransform.transform.position;
var projectile = Instantiate(projectilePrefab, projectileSpawnPoint.position, projectileSpawnPoint.rotation);
projectile.GetComponent<Rigidbody>().velocity = projectileSpawnPoint.forward * bulletSpeed;
Destroy(projectile, bulletLife);
For destroying the projectile afterward you can keep it as you have it in OnCollision. howeer, with bullets in particular, since they tend to be instantiated A LOT and then destroyed afterward it would be best to use an object pooler for them to instantiate several of them on start and then disable and enable them as needed so you can resuse them instead of making new ones every time.
you have to create a new script that derives from Monobehaviour for your projectiles. attach that script to the projectile prefab and place the OnCollisionEnter method in that script. now your projectiles should get destroyed when touching another collider. make sure that there is a rigidbody component attached to the projectile.
I am trying to create a script for my enemy turret, but it is not going well. I have a couple animations of the turret being activated and deactivated. What I need is that based on the distance from the player, it plays either animation. So once it moves inside the detection radius it plays the activation animation and once it is outside it plays the deactivation animation. Most of the other ways I try require me to create an Animation Controller, which I have little experience in using. I want a simple way to play one animation once it is inside and play a different one when it is outside. I think there was a way to store the animation clip in the script, and then play it. I have attached my current script, so you know what I mean.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyTurret : MonoBehaviour
{
public GameObject Player;
public float DistanceToPlayer;
public float DetectionRadius = 75;
// Start is called before the first frame update
void Start()
{
Player = GameObject.FindGameObjectWithTag("PlayerTank");
}
// Update is called once per frame
void Update()
{
DistanceToPlayer = Vector3.Distance(transform.position, Player.transform.position);
if (DistanceToPlayer<=DetectionRadius)
{
Debug.Log("Within Radius");
}
if (DistanceToPlayer >= DetectionRadius)
{
Debug.Log("Outside Radius");
}
}
}
Calculating and checking the distance of the player for every update() is not ideal. It will work, but it will do more work than it needs to when the player isn't even near it. Its not efficient.
What you may want to do if your player is a Rigidbody, is add a SphereCollider to the turret, set isTrigger=true, set the radius to be your detection radius, and handle the OnTriggerEnter() and OnTriggerExit() events to play or stop animations.
You can also add two public Animiation objects to the script, drag and drop your animations in the editor, then you can use animation.Play() and .Stop() etc. to control the animations.
Something similar to this. Not tested fully, but you can get the idea.
public float detectionRadius = 75;
public Animation activateAnimation;
public Animation deactivateAnimation;
void Start()
{
SphereCollider detectionSphere = gameObject.AddComponent<SphereCollider>();
detectionSphere.isTrigger = true;
detectionSphere.radius = detectionRadius;
detectionSphere.center = Vector3.zero;
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "PlayerTank")
{
activateAnimation.Play();
}
}
private void OnTriggerExit(Collider other)
{
if (other.gameObject.tag == "PlayerTank")
{
deactivateAnimation.Play();
}
}
Your animations must not loop otherwise you will have to add more logic to check if animation.isPlaying and do your own animation.Stop() etc.
So I wrote some code to make an object rotate if I swiped left or right
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotater : MonoBehaviour {
public Transform player;
void Update()
{
if (Input.touchCount == 1)
{
// GET TOUCH 0
Touch touch0 = Input.GetTouch(0);
// APPLY ROTATION
if (touch0.phase == TouchPhase.Moved)
{
player.transform.Rotate(0f, 0f, touch0.deltaPosition.x);
}
}
}
}
and the problem is when I swipe fast the rotation will be uncontrollable. So I want the input to be less sensitive.
my goal is for the rotation to be like rolly vortex
my setup:
I made an empty object and put it in the center
made the empty object a parent of my player
and finally, I put my code in the empty object
this setup made the player rotate in sort of an orbit which like I told you is similar to rolly vortex.
First you want to be able to scale the sensitivity. This means making it so that for every unit of change in touch position, you will get some multiple of a unit of change in the rotation. For this, make a configurable (public) member variable, public float touchSensitivityScale, and multiply the rotation by that value. Example:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotater : MonoBehaviour {
public Transform player;
public float touchSensitivityScale;
void Update()
{
if (Input.touchCount == 1)
{
// GET TOUCH 0
Touch touch0 = Input.GetTouch(0);
// APPLY ROTATION
if (touch0.phase == TouchPhase.Moved)
{
player.transform.Rotate(0f, 0f, touch0.deltaPosition.x * touchSensitivityScale);
}
}
}
}
Now you can edit the touch sensitivity in the inspector. With touchSensitivityScale set to 1, the behavior will be identical to what it is currently. If you make the number 0.5, the rotation will be half as sensitive.
If this doesn't fully solve the problem and you also want some smoothing or acceleration, that might warrant an edit to the question.
I hope it helps!
Rather than rotating by touch0.deltaPosition.x you could always have some sort of negative exponential function. In this case it’d probably be something along the lines of e^(-x-a) where x is your touch0.deltaPosition.x, and a would be a variable you’d have to determine based on how fast you want the initial speed of rotation. If you’re not familiar with exponential functions try using a graphing software like Desmos to plot y=e^(-x-a) and vary the value of a. Once you’ve visualised that it should be pretty self explanatory.
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);
}
}
}