I am working on a small game for a school project, in which my player needs to attack enemies in a level. My plan is to have a collider that is enabled in an attached script, and then disabled when the attack is done. My current problem is that that the collider does not flip the way it is supposed to, it seems to flip directly on the overall x axis instead of flipping in the x axis related to the player. It is a child of the player so I am clueless as to why it is doing this. Any solutions or other approaches would be greatly appreciated. I will attach the current script that controls the collider below.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class VerticalSword : MonoBehaviour
{
//Variables use to active the colliders
Collider2D AttackColliderVertical;
//Variables for the location of the collider
Vector2 attackOffset;
private void Start()
{
AttackColliderVertical = GetComponent<Collider2D>();
attackOffset = transform.position;
AttackColliderVertical.enabled = false;
}
public void FixedUpdate()
{
attackOffset = transform.position;
}
public void AttackUp()
{
AttackColliderVertical.enabled = true;
if (attackOffset.y > 0)
{
transform.position = attackOffset;
}
else if (attackOffset.y < 0)
{
transform.position = new Vector2(attackOffset.x, (attackOffset.y * -1)); //I think the problem is somewhere in this if and else if statement
}
print("Attack up successful"); //Error checking (This works when run)
}
public void AttackDown()
{
AttackColliderVertical.enabled = true;
if (attackOffset.y > 0)
{
transform.position = new Vector2(attackOffset.x, (attackOffset.y * -1));
}
else if (attackOffset.y < 0)
{
transform.position = attackOffset; //I think the problem is somewhere in this if and else if statement
}
print("Attack down successful"); //Error checking (This works when run)
}
public void StopAttack()
{
AttackColliderVertical.enabled = false;
}
}
Use transform.localPosition, not transform.position (that's its world space position). You need to change it everywhere in this script; the Start() function and the two attack functions
Related
I'm working on a sports game where if a player skates into the goalie crease, I want all the player positions to reset to the center of the ice and do a three second countdown before play resumes.
I have tried to hardcode the starting position for the main player in a variable called PlayerStart and I call Player.transform.position = PlayerStart. When I did this, the player didn't move so I tried to switch the object I was setting as the player. This did what I wanted, but the mouse functionality changes for some reason and when the countdown ends, the player just goes right back to the position they were in before the crease violation was called.
Other things I've tried:
transform.SetPositionAndRotation
PlayerStart = Player.transform.position (instead of hard coding the numbers in)
Here is my code:
public class Crease : MonoBehaviour
{
private float Delay = 0;
private bool CreaseViolated = false;
private GameObject Player;
public Vector3 PlayerStart;
// Start is called before the first frame update
void Start()
{
Ring = GameObject.Find("Ring");
Player = GameObject.Find("FPSController");
PlayerStart = new Vector3(29.75f, 6.03999996f, 4.42000008f);
}
// Update is called once per frame
void Update()
{
Delay -= Time.deltaTime;
if (CreaseViolated)
{
CreaseViolation();
}
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.name != "Ring"
&& other.gameObject.name != "TeamGoalie"
&& other.gameObject.name != "OpponentGoalie")
{
CreaseViolated = true;
Delay = 3;
}
}
void CreaseViolation()
{
if (Delay > 0)
{
PlayerTip.GetComponent<PickupRing>().HasRing = false;
Opponent.GetComponent<AI>().HasRing = false;
Ring.transform.parent = null;
}
else
{
text.text = " ";
if (CreaseViolated)
{
Debug.Log("Player position before: " + Player.transform.position);
Player.transform.position = PlayerStart;
Debug.Log("Player position after: " + Player.transform.position);
//Player.transform.SetPositionAndRotation(PlayerStart + new Vector3(0f, 0.800000012f, 0f), new Quaternion(0f, -0.707106829f, 0f, 0.707106829f) + new Quaternion(0f, 0f, 0f, 1f));
GameObject.Find("Countdown").GetComponent<CountdownText>().timeRemaining = 4;
CreaseViolated = false;
}
}
}
}
Here is a short YouTube video showing my code and the demo: https://www.youtube.com/watch?v=mZt_4AppBh8
this problem is all solved now thanks to an awesome person at my university helping me out! The solution was disabling the CharacterController before repositioning the player and then enabling it again after.
So this:
Player.transform.position = PlayerStart;
in the CreaseViolation function becomes
cc.enabled = false;
PlayerController.transform.position = PlayerControllerStart;
cc.enabled = true;
with cc being declared earlier as
private CharacterController cc;
and in the start function I assigned it with the value
cc = Player.GetComponent<CharacterController>();
with PlayerController being set to the FPSController.
I renamed Player to PlayerController for more clarity.
Hopefully this helps anyone having the same problem I was having!
The Above answer works perfectly but might bring some issues when doing networked changes in player transform positions.
The reason the transform change doesn't work without disabling the Character Controller is because the character controller overrides the transforms.
To Disable this and enable an Auto Synchronization between transforms GoTo:
Edit > Project Settings > Physics > (Enable Auto Sync Transforms)
I have been try for a while to stop the enemy rotate wen my player collide with it. I have insert a rigid body, and I have try to freeze position and also the freeze rotation but he keep doing the same, I can't find any were any info to learn about this problem.
I have google it a few times and could not find any thing, close to my problem.
This is the screenshot of the problem
https://imgur.com/fyryuqY
Also I have tried to set Angular drag to 0 but no success it keep doing the same.
It sounds like I am missing something, but I can't find any solution for it yet.
I have also tried to see all answers on unity forum but I can't find anywhere a solution or the way to learn about this problem.
I have edit to insert the enemy script
This is my enemy script
using UnityEngine;
using System.Collections;
public class target : MonoBehaviour {
public float health = 100f;
public Animator animx2;
public AudioSource audiovfx2;
public void TakeDamage (float amount)
{
health -= amount;
if (health <= 0f)
{
Die();
}
}
void Die()
{
animx2.SetBool("isdie",true);
audiovfx2.Play();
healthcontroller.score += 10;
health -= 10;
Destroy (gameObject, 1.5f);
}
void Update()
{
animx2 = GetComponent<Animator>();
GetComponent<AudioSource>().Play();
}
void OnTriggerEnter(Collider other) {
if (other.tag == "Player") {
Rigidbody rb = GetComponent<Rigidbody>();
rb.angularVelocity = Vector3.zero
//Stop Moving/Translating
//rbdy.velocity = Vector3.zero;
//Stop rotating
//rbdy.angularVelocity = Vector3.zero;
}
}
void OnTriggerExit(Collider other) {
if (other.tag == "Player") {
//here i want to return to normal
}
}
}
Thank you in advance
Did you try to nullify angularVelocity of the Rigidbody component, for example
rb.angularVelocity = Vector3.zero;
I'm currently making a game in Unity where I'm trying to get destroy the clones of a prefab only after they leave the view of the camera only after they already entered the view of the camera in the first place. However, for some reason, my code is instantly destroying the clones as soon as their instantiated. Does anyone know how I could solve this problem?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InteractControl : MonoBehaviour
{
Rigidbody2D rb;
GameObject target;
float moveSpeed;
Vector3 directionToTarget;
// Use this for initialization
void Start()
{
target = GameObject.Find("White Ball");
rb = GetComponent<Rigidbody2D>();
moveSpeed = 3f;
}
// Update is called once per frame
void Update()
{
MoveInteract();
OnBecameVisible();
}
/*void OnTriggerEnter2D(Collider2D col)
{
switch (col.gameObject.tag)
{
case "ColouredBall Highress":
BallSpawnerControl.spawnAllowed = false;
Destroy(gameObject);
target = null;
break;
case "Star":
Collision collision = new Collision();
break;
}
} */
void MoveInteract()
{
if (target != null)
{
if(ScoreScript.scoreValue > 3)
{
directionToTarget = (target.transform.position - transform.position).normalized;
rb.velocity = new Vector2(directionToTarget.x * moveSpeed,
directionToTarget.y * moveSpeed);
}
else
{
directionToTarget = new Vector3(0, -1, 0);
rb.velocity = new Vector2(0, directionToTarget.y * moveSpeed);
}
}
else
rb.velocity = Vector3.zero;
}
void OnBecameInvisible()
{
if (gameObject.tag == "ColouredBall Highress")
{
Destroy(gameObject);
}
if (gameObject.tag == "Star")
{
Destroy(gameObject);
}
}
void OnBecameVisible()
{
if (gameObject.tag == "ColouredBall Highress" || gameObject.tag == "Star")
{
OnBecameInvisible();
}
}
}
I tried to solve the problem by first requiring the objects to become visible in order for them to be able to get destroyed when out of view of the camera. In short I'm looking for the OnExit collider version for on OnBecameInvisible. I guess I could make the whole screen a collider and use on Exit collider on it. Does someone possibly also know how I could make a collider that covers the camera view?
It is because you call OnBecameInvisible() from OnBecameVisible. So when they are visible they get destroyed.
Also your code is doing so many redundant things you also call OnBecameVisiblefrom Updateetc.
You can simply use this instead:
Renderer m_Renderer;
void Start()
{
m_Renderer = GetComponent<Renderer>();
}
void Update()
{
//It means object is NOT visible in the scene if it is false is visible
if (!m_Renderer.isVisible)
{
Destroy(gameObject);
}
}
Note that: Destroying/Instantiating objects are not the best practices at this circumstance. Because it causes garbage collector to work a lot and it is expensive and can slow down your game. You can use object pooling instead. It basically puts object which are not in the field of view into an object pool and you keep their references and can use them later. Therefore, it is less costly than your method.
You are calling OnBecameVisible every frame, so basically the first frame the object destroys itself. Deleting it from Update should do the trick, Unity already calls it for you.
I want my enemy to move back to starting position. He follows me until I get out of his range and then he just stops.
Also i want my skeleton to stop for like 5 sec, and then go back to starting point, any ideas ? I never did anything involving time, exept stopping it.
Here is my script for enemy:
Also here is a screenshoot of inspector on the skeleton: enemy
Here is my script for enemy:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class chase : MonoBehaviour
{
public Transform player;
private Animator anim;
public float LookRadius = 15f;
public Transform enemyStartPos;
// Use this for initialization
void Start()
{
anim = GetComponent<Animator>();
this.enemyStartPos.position = this.transform.position;
}
// Update is called once per frame
void Update()
{
if (!PauseMenu.GameIsPaused)
{
if (Vector3.Distance(player.position, this.transform.position) < 15)
{
Vector3 direction = player.position - this.transform.position;
direction.y = 0;
this.transform.rotation = Quaternion.Slerp(this.transform.rotation, Quaternion.LookRotation(direction), 0.1f);
anim.SetBool("isIdle", false);
if (direction.magnitude > 3)
{
this.transform.Translate(0, 0, 0.05f);
anim.SetBool("isWalking", true);
anim.SetBool("isAttacking", false);
}
else
{
anim.SetBool("isAttacking", true);
anim.SetBool("isWalking", false);
}
}
else
{
if (Vector3.Distance(this.enemyStartPos.position, this.transform.position) >1)
{
Vector3 direction = this.enemyStartPos.position - this.transform.position;
direction.y = 0;
this.transform.rotation = Quaternion.Slerp(this.transform.rotation, Quaternion.LookRotation(direction), 0.1f);
anim.SetBool("isIdle", false);
if (direction.magnitude > 1)
{
this.transform.Translate(0, 0, 0.05f);
anim.SetBool("isWalking", true);
anim.SetBool("isAttacking", false);
}
}
else
anim.SetBool("isIdle", true);
anim.SetBool("isAttacking", false);
anim.SetBool("isWalking", false);
}
}
}
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, LookRadius);
}
}
Before you try to "code" this, think about it in terms of your program design. You have designed and implemented behavior that says "if the bot's position is within X units of the player's position, turn the bot and move it toward the player."
What you describe wanting to do next can be thought of in the same way (which should lead to similar code).. "else, if the bot's position is NOT within X units of the player's position, turn the bot and move it toward [origin]." Note, this means you need to define what [origin] is for the bot. Point being, it makes no difference in the code whether you are moving toward a player or some arbitrary fixed point. The code to move one transform toward another transform is the same.
For "wandering" it's essentially the same thought process: If bot is within X units of [origin] and not following player, pick a random direction and move that way. (better yet, pick a random direction and move that way for some amount of time so your bot doesn't just jitter around origin).
Hi so what im trying to create is the player can right click on an enemy and he will follow at a certain distance. which is working fine. but what i want it to also do is stop at that distance too. currently if the enemy stops he will try and go to its exact position instead of stopping a little bit away this is what i have currently.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class Attacking : MonoBehaviour {
NavMeshAgent agent;
Transform target;
public float distance;
public float followDistance;
// Use this for initialization
void Start () {
agent = GetComponent<NavMeshAgent>();
}
// Update is called once per frame
void Update () {
if (Input.GetMouseButton(0))
{
target = null;
}
if (Input.GetMouseButton(1))
{
RaycastHit hit;
if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit, 100))
{
if (hit.collider.gameObject.tag == "enemy" || hit.collider.gameObject.tag == "Player")
{
target = hit.collider.transform;
}
}
}
if(target != null)
{
distance = Vector3.Distance(transform.position, target.position);
if (followDistance <= distance)
agent.destination = target.position;
}
}
}
Attach a script to your enemy and give it a certain radius ,say 3f.
public float radius=3f;
for better understanding and visual aid use OnDrawGizmosSelected() (on your enemy script).
void OnDrawGizmosSelected ()
{
Gizmos.color=Color.yellow;
Gizmos.DrawWireSphere(transform.position,radius);
}
Now,on your player script use agent.StoppingDistance() as:
if(target != null)
{
distance = Vector3.Distance(transform.position, target.position);
if (followDistance <= distance){
agent.destination = target.position;
agent.StoppingDistance=target.radius;
}
}
Note:you will have to change target from transform to an instance of your player