Unity C#/Blender Model not rotating correctly - c#

So I created a turrent model in blender an imported into unity everything was looking good I got a little rotation script put togeather for my hub scene and rotation works good
Now moving into the code trying to rotate the barrel to look torwards the enemy doesnt look so good
Heres a short gameplay video to demonstrate the issue
Demonstration
the barrel of the turrent is facing a completly different place then the enemy I would much prefer to fix the issue in code rather then rebuilding the model from scratch so heres what Im doing currently(thats not working)
private void Update(){
FlameForgedTime.UpdateTime ();
if (isInGame) {
RegenerateHitpoint ();
//Look for enemy
if (FlameForgedTime.Time - lastAttack > StatsHelper.Instance.GetStatValue (Stat.Speed)) {
Collider[] col = Physics.OverlapSphere(transform.position,StatsHelper.Instance.GetStatValue (Stat.Range),LayerMask.GetMask("Enemy"));
if (col.Length != 0) {
//find closest enemy
int closestIndex = 0;
float dist = Vector3.SqrMagnitude (col [closestIndex].transform.position - transform.position);
for (int i = 1; i < col.Length; i++) {
float newDistance = Vector3.SqrMagnitude (col [i].transform.position - transform.position);
if (newDistance < dist) {
dist = newDistance;
closestIndex = i;
}
}
//shoot enemy
//Rotate turrent to look at enemy GameObject.FindGameObjectWithTag("Player").transform.LookAt(col[closestIndex].transform);
ShootEnemy(col[closestIndex].transform);
lastAttack = Time.time;
}
}
}
}
So on my turrent(parent gameobject) i have the tag "Player" as the turrent is loaded in a preloader scene and is not accessible by a public GameObject field
For some reason the Y is the axis the turrent rotates on
Anyways I get the closest enemy to the tower and then do a LookAt to try to get the turret to look at the enemy and then shoot at the enemy however that is not working correctly as you can see by the video

The "forward" axis on your model (that is, the direction the gun barrels point) doesn't line up with what Unity says is the forward axis.
"Forward" in Unity is along the positive Z direction, so your model doesn't line up with its transform's local forward (which is what points towards things when using LookAt()). Looks like your model is aligned with forward along the positive X axis instead.
There are three ways to fix this:
rotate it in Blender and reexport (best option)
create an empty parent GameObject that "becomes" the gun object (that is, all references point to this new object, any scripts move from where they are now to here, etc), but you put the current object inside and rotate the now-child transform by 90 degrees. This is also called "recentering" sometimes. With assets that aren't yours, this is sometimes the only option.
script-wise rotate by 90 degrees after performing a LookAt() (not recommended)

Related

How can I check the distance from each one of the cubes depending on what cube I'm closer to?

The cubes are in formation of a big square to create some kind of border so the player can't move further.
transform is the player the script is attached to the player.
When I move the player to one of the cubes close to it the distance is about 95 but it should 0.1f or 0.
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityStandardAssets.Characters.ThirdPerson;
public class DistanceCheck : MonoBehaviour
{
public Transform[] cubes;
public GameObject descriptionTextImage;
public TextMeshProUGUI text;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
for (int i = 0; i < cubes.Length; i++)
{
var dist = Vector3.Distance(transform.position, cubes[i].transform.position);
if (dist <= 0.1f)
{
descriptionTextImage.SetActive(true);
text.text = "I can't move.";
}
else
{
text.text = "";
descriptionTextImage.SetActive(false);
}
}
}
}
When I'm using a break point on the line :
if (dist <= 0.1f)
dist is a bit more then 95. Maybe the distance is checked to another cube or in another point on the cube?
You are checking all cubes every time and using same "dist" variable every time.
So it detects deistance being less then 0.1f, but goes on and changes value of dist to test another cube.This is why you are getting higher values despite being right next to a cube.
You need 4 distance variables that are each measuring distances to its specific cube and do something if either of them gets too short.
Another flaw is that you are measuring distance to a point in a box, so depending which side of a box you are its going to be showing different values.
I would suggest instead of using cube Transforms, use their Colliders instead. And then I'd be looking for the closest point on the collider bounds. As it currently stands, you're checking for the distance of this object, to the origin of the cube, and it sounds to me like you simply want to find the distance to the cube/collider in general.
First, change the field type for your cubes:
public BoxCollider[] cubes;
Then find the distance like this:
var closestPoint = cubes[ i ].ClosestPointOnBounds ( transform.position );
var distance = Vector3.Distance( transform.position, closestPoint );
Now you should be getting a distance to the closest point to the cube/collider.
More information on ClosestPointOnBounds can be found here at the Unity docs.

Instantiate a prefab pointing in the direction of another object

The Issue
I'm making a 2D Unity game where the main weapon of your character is a fireball gun. The idea is that a fireball will shoot out of the player's hand at the same angle the player's hand is pointing. I have 3 issues:
When I shoot the fireball, since the fireball is a RididBody, it pushes the player. This is because I've made the centre of the player's arm (the same place where the fireball shoots from) the point at which the arm rotates around the player (what is meant to be the shoulder);
To instantiate the fireball prefab on the arm, the only way I know how to do it is by using a piece of code which requires the arm to be a RigidBody. This means that the arm is affected by gravity and falls off the player on start unless I freeze the arm's y-axis movement, which means that when the player jumps, while the arm does not fall, it floats at the same y-position as where it started while moving along the x-axis; and
When the fireball is shot, the angle from which it is propelled after being shot is not the same angle as the angle of the player's arm.
Instantiating the Fireball
if (Input.GetKeyDown(KeyCode.Space))
{
pew.Play();
var fireballTransform = Instantiate(fireballPrefab); //creates a new shot sprite
fireballTransform.position = new Vector3(transform.position.x + horizMultiplier, transform.position.y, transform.position.z);
fireballTransform.rotation = orientation;
fireballTransform.transform.Rotate(0, 0, transform.rotation.z);
}
if (Input.GetKeyDown(KeyCode.D)) // moves right
{
orientation = 0;
horizMultiplier = 0.08F;
}
if (Input.GetKeyDown(KeyCode.A)) // moves left
{
orientation = 180;
horizMultiplier = -0.08F;
}
This piece of code is located within the script applied to the player's arm. The movement of the arm works fine and the problem seems to be either within this piece of code or the code for my fireball (which I will put next). A few definitions:
pew is a sound effect played when the fireball is shot;
horizMultiplier is the distance from the arm's centre which I would like the fireball to instantiate (also dependant of if the player) is facing left or right); and
orientation is which direction the player is facing (left or right). The fireball is then instantiated facing that same direction.
Fireball Script
public Vector2 speed = new Vector2(); // x and y forces respectively
private Rigidbody2D rb; // shorthand
private float rotation;
void Start()
{
rb = GetComponent<Rigidbody2D>(); // shorthand
rotation = rb.rotation;
if (rotation == 0)
{
rb.AddForce(Vector3.right * speed.x); // propels right
}
if (rotation == 180)
{
rb.AddForce(Vector3.left * speed.x); // propels left
}
}
I believe this code is explanatory enough with comments (if not please comment and I'll address any question). I believe an issue could also be in this piece of code because of the lines: rb.AddForce(Vector3.right * speed.x); and rb.AddForce(Vector3.left * speed.x); as these add directional forces to the object. I don't know is this is objective direction (right or left no matter what direction the object the force is being applied to is facing) or if it's right or left in terms of the object-- say if an object was rotated 90 degrees clockwise and that object had a force applied so that it moves right making the object move downwards.
What I'm expecting to happen is the player's arm will turn so that when a fireball is fired it is fired in the direction the arm is facing. The arms turning mechanics are fine, it's just trying to properly instantiate the fireball. Can anyone help with any of the issues I've laid out?
How I would go about this:
Add an empty transform as child of the arm and move it to where the fireball should spawn. Also make sure the rotation of it is such that its forward vector (the local z-axis) points to where the fireball should go. To see this, you need to set "Local" left of the play button.
Spawn the fireball at the transform's position with its rotation.
Ignore collision between the arm's/player's collider and the fireball's collider with https://docs.unity3d.com/ScriptReference/Physics.IgnoreCollision.html. If necessary, you can enable the collision between the two colliders again after 1s or so.
Set the fireball rigidbody's velocity to speed * rigidbody.forward.
If you need help with the code, please post it so I can see what's going on.
Edit:
The arm definitely doesn't require a Rigidbody.
You can just use Instantiate(prefab, position, rotation) as shorthand.
Is this for a 2D game?
Also, I'm going to sleep now but I'll gladly try to help tomorrow.
Your Issues
1) You should be masking the fireball's layer not to collide with your player's layer.
You can find more info about this here: https://docs.unity3d.com/Manual/LayerBasedCollision.html
(note: make sure you're on the Physics2D panel, and not the Physics one, as that's for 3D)
2) There is a setting called gravityScale in RigidBody2D. You should set this to 0 if you don't want gravity to be affecting your object. More info: https://docs.unity3d.com/Manual/class-Rigidbody2D.html
Fireball Instantiate
if (Input.GetKeyDown(KeyCode.Space))
{
pew.Play();
var position = hand.transform.position + hand.transform.forward * horizMultiplier;
var rotation = hand.transform.rotation;
var fireball = Instantiate<Fireball>(fireballPrefab, position, rotation);
fireball.StartMoving();
}
Fireball Script
private Rigidbody2D rb; // shorthand
private float rotation;
public float Speed;
public void StartMoving()
{
rb = GetComponent<Rigidbody2D>(); // shorthand
rb.velocity = transform.forward * Speed;
}
void OnTriggerEnter(....) { .... }

Rigidbody Mobs fall through ground while walking

I have a really odd issue, I created custom MOB AI in unity for my game (it has procedural generated voxel world so agents didn't work well). I use rigidbody on the mobs which I move around.
But I have this issue where mobs go inside the floor while moving (doesn't happen when standing) and when they stand, they teleport back up!. It's not animation, I disabled animations and it still happens.
here is how I move them:
private void WalkToTarget()
{
if (goal != Vector3.zero)
{
if (goal.y <= 5)
{
currentstatus = MOBSTATUS.STANDING;
return;
}
var distance = Vector3.Distance(VoxelPlayPlayer.instance.transform.position, gameObject.transform.position);
if (distance < 15)
{
goal = VoxelPlayPlayer.instance.transform.position;
goal.y = VoxelPlayEnvironment.instance.GetHeight(goal);
}
if (distance < 5)
{
this.currentstatus = MOBSTATUS.ATTACKING;
}
//MOVEMENT HAPPENS HERE
Vector3 direction = (goal - mobcontroller.transform.position).normalized*2f;
if(mobcontroller.collisionFlags!=CollisionFlags.CollidedBelow)
direction+= Vector3.down;
mobcontroller.Move(direction * Time.fixedDeltaTime);
RotateTowards(direction);
}
}
Edit:
All code: https://pastebin.com/khCmfKGi
Part of your problem is that you are using CollisionFlags incorrectly.
Instead of this:
if(mobcontroller.collisionFlags!=CollisionFlags.CollidedBelow)
You need to do this
if(mobcontroller.collisionFlags & CollisionFlags.CollidedBelow)
Because you are trying to check if the mob is at least colliding below, not if the mob is only colliding below.
Even then, CharacterController.Move should not move you through colliders on its own.
I suspect that RotateTowards(direction) might be rotating the boundaries of mob's collider through the ground in some cases. To prevent that, I recommend creating a lookDirection that keeps the character rotation flat when you do your RotateTowards:
Vector3 direction = (goal - mobcontroller.transform.position).normalized*2f;
if(mobcontroller.collisionFlags & CollisionFlags.CollidedBelow)
direction+= Vector3.down;
mobcontroller.Move(direction * Time.fixedDeltaTime);
Vector3 lookDirection = (goal - mobController.transform.position);
lookDirection.y = mobController.transform.y;
RotateTowards(lookDirection);
This problem happened when using Rigidbody and CharacterController on the mob. Removing Rigidbody from the mob solved this problem.

Unity2D C# Randomly Spawn GameObject in an Area over another GameObject

I'm new to Unity2D (Unity 5.0.2f1) and have been searching for a solution which I'm sure is staring me in the face!
I have a game object (essentially a road) like below (DirtTrack1):
I have a spawner which spawns GameObjects (vehicles). I want to spawn those vehicles over this road.
I have tried the following code to do this, essentially trying to spawn the vehicle within the Y-axis area of the road by getting the bottom Y co-ordinate of the road and the top Y co-ordinate, so I get the min and max vertical positions of where I can place the vehicle:
void FixedUpdate() {
// Repeat spawning after the period spawn
// route has finished.
if (!_inSpawningIteration)
StartCoroutine (SpawnVehiclePeriodically());
}
IEnumerator SpawnVehiclePeriodically()
{
// First, get the height of the vehicle and road.
float vehicleHeightHalf = vehiclePreFab.GetComponent<SpriteRenderer>().bounds.size.y / 2f;
float roadHeightHalf = roadObject.GetComponent<SpriteRenderer>().bounds.size.y / 2f;
float roadTopY = roadObject.transform.position.y + roadHeightHalf;
float roadBottomY = roadObject.transform.position.y - roadHeightHalf;
// Next, ensure that maxY is within bounds of this farm vehicle.
roadMaxY = roadTopY - vehicleHeightHalf;
roadMinY = roadBottomY + vehicleHeightHalf;
// Set the position and spawn.
Vector3 newPosition = new Vector3 (Const_RoadItemsPositionX, randomY, 0f);
GameObject vehicle = (GameObject)GameObject.Instantiate (vehiclePreFab, newPosition, Quaternion.identity);
}
This does spawn randomly but most times it is always not within the road itself. It is either part on the road or at the outside edge of it.
I can't figure out what I'm doing wrong here but I'm sure it is something very simple!
Tick the kinematic check of your vehicle, physics may be moving it out of the road if you don't do that.
You are using localPosition. From documentation:
Position of the transform relative to the parent transform.
If the transform has no parent, it is the same as Transform.position.
Looking at your scene, your road has a parent object and the relative position you are getting might be messing up with the spawn position of cars.

Why the waypoints are working when they are spheres but with cylinder not?

The waypoints example is from the unity docs tutorial site.
When i put two spheres the enemies will go between them and also not good when they get to one way point they are not turning back sharp 180 degrees but they are like moving backward without turning and then turning. What i want to do is when they get to a way point to turn sharp 180 degrees on the place then to start walking to the other way point. How can i do it ? Shoud i add a state in the animator for that ?
The second problem is when i put the cylinder as waypoint with one sphere the enemies will go to the sphere and will stay there then will make rounds around the sphere they will never get to the cylinder.
This is a screenshot of the scene after baking it.
I set the Terrain to be Navigation Static and Walkable.
I also set the Spheres and the Cylinder to be Naviagtion Static and Walkable.
Guard and Guard 1 are the enemies(ThirdPersonController)
This is a screenshot of the scene the two enemies of the left the two spheres and the big cylinder.
This is the patrol script:
using UnityEngine;
using System.Collections;
public class Ai : MonoBehaviour {
public Transform[] points;
private int destPoint = 0;
private NavMeshAgent agent;
// Use this for initialization
void Start () {
agent = GetComponent<NavMeshAgent> ();
agent.autoBraking = false;
GotoNextPoint ();
}
void GotoNextPoint()
{
if (points.Length == 0)
return;
agent.destination = points [destPoint].position;
destPoint = (destPoint + 1) % points.Length;
}
// Update is called once per frame
void Update () {
if (agent.remainingDistance < 1.5f)
GotoNextPoint ();
}
}
This is a shot video clip i recorded show how they are patrolling.
And also the main player is getting angry all the time not sure why.
Clip

Categories