I am trying to achieve an endless runner that Instantiates tiled (modular) models randomly onto one another as you run along.
Here is the code attached to the model, when it triggers with "Player", it instantiates a new model randomly from an array. However, I want it to spawn in at exactly -90x from the previous model so that they tile. At the moment, it instantiates into world space at -90, 0 , 0.
function OnTriggerEnter (hit : Collider) {
//obstacles spawn
if(hit.gameObject.tag == "Player") {
var toSpawn : GameObject = obstacles[Random.Range(0,obstacles.Length)];
var spawnPosition = new Vector3 (-90,0,0);
var Spawn = Instantiate (toSpawn, spawnPosition), Quaternion.identity;
}
}
You could keep a count of how many tiles have already been placed, and use it as a multiplier.
private int tileCount = 1;
and in your OnTriggerEnter() method:
var offset = new Vector3 (-90 * tileCount,0,0);
tileCount++;
you need to cache the old tile then or find it somehow
GameObject lastSpawn;
function OnTriggerEnter (hit : Collider)
{
//obstacles spawn
if(hit.gameObject.tag == "Player")
{
var toSpawn : GameObject = obstacles[Random.Range(0,obstacles.Length)];
var offset = new Vector3 (-90,0,0);
var spawn = Instantiate (toSpawn, lastSpawn.transform.position + offset), Quaternion.identity) as GameObject;
lastTile = spawn;
}
}
now this one will allow for variable tile sizes (not tested):
GameObject lastSpawn;
function OnTriggerEnter (hit : Collider)
{
//obstacles spawn
if(hit.gameObject.tag == "Player")
{
var toSpawn : GameObject = obstacles[Random.Range(0,obstacles.Length)];
var offset = lastSpawn.GetComponent<MeshRenderer>().bounds.extents + gameObject.GetComponent<MeshRenderer>().bounds.extents;
offset.y = 0f;
var spawn = Instantiate (toSpawn, lastSpawn.transform.position + offset), Quaternion.identity) as GameObject;
lastTile = spawn;
}
}
Related
The enemy must look at the player if the player comes into view. Below is the code how I did it. The problem is that the enemy sees the player through the wall. How can I fix the code so that the enemy does not see the player through obstacles?
I came up with this solution - to filter out all hits to the player, and then additionally filter out those that do not pass through the barrier. However, I don't know how to implement it.
RaycastHit[] hitsInfo = Physics.SphereCastAll(head.position, sightDistance, transform.forward, sightDistance);
for (int i = 0; i < hitsInfo.Length; i++)
if (hitsInfo[i].transform.gameObject.tag == "Player") {
transform.LookAt(hitsInfo[i].transform.position);
transform.eulerAngles = new Vector3(0, transform.eulerAngles.y, 0);
Debug.DrawLine(head.position, hitsInfo[i].transform.position, Color.red, 0.05f, true);
break;
}
Below is an illustration: the player is white, the enemy is blue, the red is a raycast visualization.
You can use math to check whether the player in sight or not and than use raycast to filter all obstacles.
Here is an example:
using UnityEngine;
public class Enemy : MonoBehaviour
{
[SerializeField] private Transform _objectOfInterest;
[SerializeField] private float _sightAngle = 60f;
[SerializeField] private float _maxDistance = 10f;
private void Update()
{
if (InSight(_objectOfInterest))
{
Debug.Log("InSight");
if (BehindObstacle((_objectOfInterest)))
{
Debug.Log("BehindObstacle");
}
}
}
private bool InSight(Transform objectOfInterest)
{
var forwardDirection = transform.forward;
var directionToTarget = objectOfInterest.position - transform.position;
var angle = Mathf.Acos(Vector3.Dot(forwardDirection.normalized, directionToTarget.normalized));
if (angle * 100 <= _sightAngle) return true;
return false;
}
private bool BehindObstacle(Transform objectOfInterest)
{
var direction = objectOfInterest.position - transform.position;
var raycastDistance = direction.magnitude < _maxDistance ? direction.magnitude : _maxDistance;
var ray = new Ray(transform.position, direction.normalized);
var hits = new RaycastHit[16];
var hitsAmount = Physics.RaycastNonAlloc(ray, hits, raycastDistance);
Debug.DrawRay(transform.position, direction.normalized * raycastDistance);
if (hitsAmount == 0) return true;
foreach (var hit in hits)
{
if (hit.transform.TryGetComponent<Player>(out Player player) == false) // Player is empty MonoBehaviour in my case
{
return true;
}
return false;
}
return false;
}
}
All the math are in InSight method. forwardDirection is the direction where an enemy is looking. When we use "targetposition" - "myposition" in directionToTarget we getting vector that pointing from our position to target. Than we use simple function to get the angle at which the player is in relation to the enemy. The function is - angle = Acos(Dot(A, B)) where A and B are normalized vectors.
In BehindObstacle we just making raycast to player position and if there are any obstacle returning true. You can set sight angle and max distance on your opinion.
And don't use this in Update method (i'm using it only for test) or very often, it can cause performance issues.
How would I delete an enemy on the enemyprefab but not the enemanim animator?
#pragma strict
var enemy : GameObject;
var speed : float = 1.0;
var enemanim : Animator;
function Start() {
this.transform.position.x = 8.325;
this.transform.position.y = -1.3;
enemanim = this.GetComponent(Animator);
enemanim.SetFloat("isdead", 0);
}
function OnCollisionEnter2D(coll: Collision2D) {
if (coll.gameObject.CompareTag("distroy")) {
Destroy(this.gameObject);
}
}
function enemstruck() {
enemanim.SetFloat("isdead", 1);
}
function FixedUpdate() {
this.transform.Translate(Vector3(Input.GetAxis("Horizontal") * speed * Time.deltaTime, 0, 0));
this.rigidbody2D.velocity = Vector2(-5, 0);
}
This is my enemy prefab code i am instantiating it in my main
These 2 var:
var enemytrans : Transform;
var enemy : GameObject;
function Start () {
while (true) {
yield WaitForSeconds (Random.Range(3, 0));
enemy = Instantiate(enemytrans).gameObject;
}
I think you cannot delete GameObject and save one of its components. Every component needs to be attached to some GameObject and you cannot move them to other GameObjects either.
What you can do is to remove other components from your GameObject and you will get the same result.
You can remove a component with following script:
Destroy(gameObject.GetComponent(yourComponent));
It is possible to save the Component and Destroy the GameObject. Although I can only think of very few special cases when this would be done with logic (not out of madness).
For example, you might have different enemies, when one dies, its special power transfers over to another enemy via the Component.
So this is how I would do it, using the example above (code is C# because UnityScript lacks power):
public void die()
{
Component c = GetComponent<TheType>();
// Send component.
BroadcastMessage("setComponent", c);
// Destroy.
Destroy(gameObject);
}
Then whatever object is listening to setComponent will handle it:
public void setComponent(Component c)
{
gameObject.AddComponent<c>();
}
I have never done this before, but it came out so awesome that now I am going to add it to one of my games
i have tried everything to get the destroy to work Destroy(enemytrans) Destroy(enemy) Destroy(enemy.gameObject..... ect all abbreviations wont work.
can someone please help ???
i can coll with all objects and they do destroy but if 2 enemies are on screen i hit the one closest to me the other one will die because it was last spawned how can i destroy the one i jump on ?? mind efukd. :(
var Player : GameObject;
var Gravity:float = 2;
var speed:float = 2;
var enemytrans : Transform;
var enemy: GameObject;
public var jumped = false;
var anim : Animator;
function Start () {
while (true) {
yield WaitForSeconds (Random.Range(3, 0));
enemy = Instantiate(enemytrans).gameObject;
}
anim = GetComponent(Animator);
// Instantiate the prefab and put the gameObject into "theCube"
}
function Update () {
Player.transform.position.x = -4.325;
//the gravity function
if (jumped == false){
anim.SetFloat("hf",0.0);
}
if (Input.GetButtonDown("Fire1") && jumped==false){
fire();
jumped = true;
}
if(jumped==true){
anim.SetFloat("hf",1);
}
}
function OnCollisionEnter2D(coll: Collision2D) {
if(coll.gameObject.CompareTag("ground")){
anim.SetFloat("hf",0.0);
jumped=false;
}
if(coll.gameObject.CompareTag("enemy") && jumped==true){
fire();
jumped=true;
Destroy(enemy,1);***********************************************this line************
}
if(coll.gameObject.CompareTag("enemy") && jumped==false){
Destroy(Player);
}
}
function fire(){
Player.transform.Translate(Vector3(Input.GetAxis("Vertical") * speed * Time.deltaTime, 0, 0));
Player.rigidbody2D.velocity = Vector2(0,10);
}
Problem
You are destroying the last spawned GameObject, which you keep a reference to in the enemy variable.
Solution
You should destroy what you hit. Unity3D already gives you who you collided against so just use that information.
function OnCollisionEnter2D(coll: Collision2D)
{
if(coll.gameObject.CompareTag("enemy") && jumped==true)
Destroy(coll.gameObject);
}
i have added a animator to the enemy prefab and i want to make the animation change when i hit it
in the collision ( its **** out ) please can someone help me:(
i tried to make a new var eanim : Animator.... and call it in the start ect... but wont let me drag the ememy animator into the slot
how can i fix this please.
outline what i want to do i want to coll with the enemy and have the enemy that i hit change to death animation.
var Player : GameObject;
var Gravity:float = 2;
var speed:float = 2;
var enemytrans : Transform;
var enemy: GameObject;
public var jumped = false;
var anim : Animator;
function Start () {
while (true) {
yield WaitForSeconds (Random.Range(3, 0));
enemy = Instantiate(enemytrans).gameObject;
}
anim = GetComponent(Animator);
}
function Update () {
Player.transform.position.x = -4.325;
if (jumped == false){
anim.SetFloat("hf",0.0);
}
if (Input.GetButtonDown("Fire1") && jumped==false){
fire();
jumped = true;
}
if(jumped==true){
anim.SetFloat("hf",1);
}
}
function OnCollisionEnter2D(coll: Collision2D) {
if(coll.gameObject.CompareTag("ground")){
anim.SetFloat("hf",0.0);
jumped=false;
}
*********if(coll.gameObject.CompareTag("enemy") && jumped==true){ **
fire();
jumped=true;
anim.SetTrigger("isdead"); <<<<<<<<<<<<<----- this is what i need help with ------
}
if(coll.gameObject.CompareTag("enemy") && jumped==false){
Destroy(Player);
}
}
function fire(){
Player.transform.Translate(Vector3(Input.GetAxis("Vertical") * speed * Time.deltaTime, 0, 0));
Player.rigidbody2D.velocity = Vector2(0,10);
}
If you do anim.SetTrigger(..) in unity, you also need to setup that inside the Animator window for the corresponding gameobject.
So select your gameobject and go to window -> animator, add a trigger parameter (in your case with the name of "isdead") - and setup the transitions from the different states. So for example I create an empty state and set that as default, and then drag between that and my animation state in order to get the transitions.
Inside the transitions you just set default -> anim state to use the "isdead" parameter under the conditions. And on anim state -> default you set exit time as the condition.
var respawn : Transform;
var dead : boolean = false;
function OnTriggerEnter(theCollision : Collider)
{
if(theCollision.gameObject.name=="Spotlight")
{
Destroy(gameObject);
Debug.Log("Dead");
dead = true;
}
}
function Respawn()
{
if(dead == true)
{
Instantiate(respawn, Vector3(0,0,0), Quaternion.identity);
}
}
I'm having trouble getting my enemies to re-spawn, at the moment I have just the one enemy following me around. I'm trying to re-spawn his after he collides with my spotlight.
I have a prefab Enemy that I want to use to create more instances of Enemy once it gets destroyed.
I'm pretty sure my code above is destroying the prefab itself and thus cannot create any more instances but I'm not sure how to just destroy an instance of a prefab. The code above is attached to my enemy.
I am pretty sure you are destroying the gameObject with the script.
if(theCollision.gameObject.name=="Spotlight")
{
Destroy(gameObject);
Debug.Log("Dead");
dead = true;
}
You should have there Destroy(theCollision.gameObject) instead.
And destroy at the end of the code block, not beginning.
Also Respawn function should be on Update or something for it to work, also you can call Respawn on the trigger function before destroying and it should spawn a new one every time.
Do not forget to reference the prefab from you Project window not Hierarchy.
As I said in my comment, you need to keep track of the time since the enemy died, and the best place to do that is in your respawner object. Here is an example implementation of it:
Respawner.js
#pragma strict
var enemyToSpawn : Enemy;
var respawnTime : int = 10; //In seconds.
private var dead : boolean = true;
private var deadTime : int = 0; //Time the enemy died, keep at 0
private var nextRespawn : int = 0;
private function Respawn() {
var enemy : GameObject = GameObject.Instantiate(enemyToSpawn.gameObject, transform.position, transform.rotation);
enemy.GetComponent(Enemy).respawner = this;
}
function Update() {
if (Time.time >= nextRespawn && dead) { //If the time is due and the enemy is dead
Respawn(); //create a new enemy
dead = false; //and tell our script it is alive
}
}
function EnemyDied(theEnemy : Enemy) {
dead = true;
deadTime = Time.time;
nextRespawn = Time.time+respawnTime;
GameObject.Destroy(theEnemy.gameObject);
}
Enemy.js
#pragma strict
public var respawner : Respawner; // The respawner associated with this enemy
function OnTriggerEnter(collision : Collider) {
if (collision.gameObject.name.Equals("Spotlight")) {
respawner.SendMessage("EnemyDied", this); //Tell the respawner to kill us
}
}
Of course your enemy class will have anything else necessary to be an actual enemy, and your respawner could have an effect. This is just an example and shouldn't be blindly copy-pasted.