[Shooter 2D]Tirer en fonction d'une rotation [C#][RESOLU]
[Shooter 2D]Tirer en fonction d'une rotation [C#][RESOLU]
Bonjour à tous,
je fais face à un petit problème pour orienter des projectiles (mettre la bonne direction)en fonction de la rotation d'une arme.
Le principe : j'ai un vaisseau composé de deux sprites qui tire des projectiles(prefab) principal et des projectiles secondaire(prefab) au moyen d'une petite tourelle( sprite enfant) que je fais pivoté sur l'axe des Z(en gros une rotation de 0° à 360°) on peut comparer ça à un char d'assaut qui roule et qui stop pour tirer dans toutes les directions avec le canon.
Le contrôle /déplacement du vaisseau est défini comme ceci :
La procédure que je veux mettre en place :
Variable bool "Pilotage automatique"
si "False"
alors
la tourelle et le tire secondaire sont désactivés.
le vaisseau se déplace en fonction des flèches du clavier (axe X, Y).
les projectiles principal sont tirés en fonction de la position du vaisseau avec une trajectoire incrémenté sur l'axe X.
Si "true"
alors
le vaisseau reste à sa position courante et ne peut plus être déplacé.
le tire principal est désactivé.
la tourelle et le tire secondaire sont activés.
la tourelle peut être orienté en fonction des fléchés du clavier. (transform.Rotate)
les projectiles secondaire sont tirés en fonction de la position de la tourelle sur le vaisseau et de la rotation de la tourelle.
Mon souci se situe au niveau du tire secondaire et plus précisément pour lui donner la bonne trajectoire sur les axe X,Y en fonction de l'angle de rotation de la tourelle, surement un problème de trigo.
Si quelqu'un veut bien m'éclairer sur les méthodes à utiliser pour faire se calcule ça serait cool.
En espérant mettre bien expliqué, merci pour votre aide.
je fais face à un petit problème pour orienter des projectiles (mettre la bonne direction)en fonction de la rotation d'une arme.
Le principe : j'ai un vaisseau composé de deux sprites qui tire des projectiles(prefab) principal et des projectiles secondaire(prefab) au moyen d'une petite tourelle( sprite enfant) que je fais pivoté sur l'axe des Z(en gros une rotation de 0° à 360°) on peut comparer ça à un char d'assaut qui roule et qui stop pour tirer dans toutes les directions avec le canon.
Le contrôle /déplacement du vaisseau est défini comme ceci :
La procédure que je veux mettre en place :
Variable bool "Pilotage automatique"
si "False"
alors
la tourelle et le tire secondaire sont désactivés.
le vaisseau se déplace en fonction des flèches du clavier (axe X, Y).
les projectiles principal sont tirés en fonction de la position du vaisseau avec une trajectoire incrémenté sur l'axe X.
Si "true"
alors
le vaisseau reste à sa position courante et ne peut plus être déplacé.
le tire principal est désactivé.
la tourelle et le tire secondaire sont activés.
la tourelle peut être orienté en fonction des fléchés du clavier. (transform.Rotate)
les projectiles secondaire sont tirés en fonction de la position de la tourelle sur le vaisseau et de la rotation de la tourelle.
Mon souci se situe au niveau du tire secondaire et plus précisément pour lui donner la bonne trajectoire sur les axe X,Y en fonction de l'angle de rotation de la tourelle, surement un problème de trigo.
Si quelqu'un veut bien m'éclairer sur les méthodes à utiliser pour faire se calcule ça serait cool.
En espérant mettre bien expliqué, merci pour votre aide.
Dernière édition par izidor le 29 Nov 2016 21:41, édité 1 fois.
Re: Tirer en fonction d'une rotation [2D]
Bonsoir,
normalement il n'y a pas besoin de trigo pour déterminer l’endroit où doit spawner (apparaître) le projectile secondaire.
Ce que je ferais :
Mettre un Empty enfant de la tourelle secondaire.
Placer cet Empty au bout du canon, à l'endroit où doit apparaître le projectil secondaire.
Faire apparaître le prefab du projectile secondaire à l'endroit de l'empty
Faire => transform.foward du projectil = transform.forward de la tourelle secondaire.
AddForce sur transform.foward du projectil.
normalement il n'y a pas besoin de trigo pour déterminer l’endroit où doit spawner (apparaître) le projectile secondaire.
Ce que je ferais :
Mettre un Empty enfant de la tourelle secondaire.
Placer cet Empty au bout du canon, à l'endroit où doit apparaître le projectil secondaire.
Faire apparaître le prefab du projectile secondaire à l'endroit de l'empty
Faire => transform.foward du projectil = transform.forward de la tourelle secondaire.
AddForce sur transform.foward du projectil.
Re: Tirer en fonction d'une rotation [2D]
Merci pour ta réponse,
C'est bon j'ai trouvé
ScritpBullet.cs
ScriptTourelle.cs
C'est bon j'ai trouvé
ScritpBullet.cs
Code : Tout sélectionner
using UnityEngine;
using System.Collections;
public class ScriptBullet : MonoBehaviour
{
public float speed=0.5f;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
float power = speed * Time.deltaTime;
transform.Translate( Vector3.up * power);
}
}
Code : Tout sélectionner
using UnityEngine;
using System.Collections;
public class ScriptTourelle : MonoBehaviour
{
public float speed=10;
public GameObject player;
public GameObject bullet;//Prefab bullet
public GameObject bulletPosition;//Objet empty
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
bool locked=player.GetComponent<ScriptPlayer>().automaticSteering;
if (locked == true)
{
float inputY = Input.GetAxis ("Vertical");
transform.Rotate (0, 0, (Time.deltaTime * inputY) * speed);
if(Input.GetKeyDown("space"))
{
GameObject shot=(GameObject)Instantiate(bullet, bulletPosition.transform.position, Quaternion.identity);
shot.transform.rotation=transform.rotation;
}
}
}
}
Re: Tirer en fonction d'une rotation [2D]
Bonjour,
Super, comme ton problème est résolu, peux-tu éditer ton premier poste et modifier le titre pour y rajouter [Résolu] au début.
Sinon, il faut que tu optimise ton code.
Il ne faut pas mettre de GetComponent dans une boucle Update, mais dans la boucle Start.
Il faut éviter de créer des variables recréées à chaque boucle dans l'Update.
C'est le cas pour le script : "ScriptBullet"
avec la variable "float power = speed"
Dans le script "ScriptTourelle":
"bool locked=player.GetComponent<ScriptPlayer>().automaticSteering;" => Double Combo en une ligne!
"float inputY"
Une très bonne explication du pourquoi du comment :
Optimizing garbage collection in Unity games
(Merci Max )
En suite, ton script instancie des boulettes à gogo, mais jamais elles ne se détruisent!!
Dans le Script "ScriptBullet" dans la boucle Start il faut rajouter l'instruction Destroy l'objet au bout de x secondes...
Super, comme ton problème est résolu, peux-tu éditer ton premier poste et modifier le titre pour y rajouter [Résolu] au début.
Sinon, il faut que tu optimise ton code.
Il ne faut pas mettre de GetComponent dans une boucle Update, mais dans la boucle Start.
Il faut éviter de créer des variables recréées à chaque boucle dans l'Update.
C'est le cas pour le script : "ScriptBullet"
avec la variable "float power = speed"
Dans le script "ScriptTourelle":
"bool locked=player.GetComponent<ScriptPlayer>().automaticSteering;" => Double Combo en une ligne!
"float inputY"
Une très bonne explication du pourquoi du comment :
Optimizing garbage collection in Unity games
(Merci Max )
En suite, ton script instancie des boulettes à gogo, mais jamais elles ne se détruisent!!
Dans le Script "ScriptBullet" dans la boucle Start il faut rajouter l'instruction Destroy l'objet au bout de x secondes...
Re: Tirer en fonction d'une rotation [2D]
Merci, justement j'allais optimisé tous ça ce soire, je remettrai un script plus propre en ligne.
pour le coup la variable "locked" va passé à "private bool locked"
puis sera initialisé dans "start()", je pourai donc la lire dans "update()"
de même pour "power" saut qu'elle sera initialisé dans "update()"
Edit
pour le coup la variable "locked" va passé à "private bool locked"
puis sera initialisé dans "start()", je pourai donc la lire dans "update()"
de même pour "power" saut qu'elle sera initialisé dans "update()"
Edit
Code : Tout sélectionner
using UnityEngine;
using System.Collections;
public class ScriptTourelle : MonoBehaviour
{
public float speed=10f;
public GameObject player;
public GameObject bullet;//Prefab bullet
public GameObject bulletPosition;//Objet empty
private bool locked;
private float inputY;
// Use this for initialization
void Start ()
{
locked=player.GetComponent<ScriptPlayer>().automaticSteering;
}
// Update is called once per frame
void Update ()
{
if (locked == true)
{
inputY = Input.GetAxis ("Vertical");
transform.Rotate (0, 0, (Time.deltaTime * inputY) * speed);
if(Input.GetKeyDown("space"))
{
GameObject shot=(GameObject)Instantiate(bullet, bulletPosition.transform.position, Quaternion.identity);
shot.transform.rotation=transform.rotation;
}
}
}
}
Code : Tout sélectionner
using UnityEngine;
using System.Collections;
public class ScriptBullet : MonoBehaviour
{
public float speed=0.5f;
private float power;
private Vector2 max;
// Use this for initialization
void Start ()
{
power = 0.0f;
max= Camera.main.ViewportToWorldPoint(new Vector2(1,1));
}
// Update is called once per frame
void Update ()
{
power = speed * Time.deltaTime;
transform.Translate( Vector3.up * power);
if ((transform.position.x > max.x) || (transform.position.y > max.y))
{
Destroy(gameObject);
}
}
}
Re: [Shooter 2D]Tirer en fonction d'une rotation [C#][RESOLU]
Nouveau petit souci,
Alors je n’arrive pas à identifier ou ce situe le problème, la tourelle est activé (variable automaticSteering==true) pendant 10 seconde via un timer, pendant ces 10 seconde des instance de" bullet " son créer puis détruit lorsqu'ils sortent du champ de la caméra, au bout des 10 seconde, je remet la variable "automaticSteering=false", réinitialise le timer à 10 seconde et remet l'angle Z de la tourelle dans ça position initiale mais, les derniers bullet instanciés ne sont pas détruits .
Si vous avez des idées, merci
Sinon je vais voir si cela change quelque chose en utilisant un timer au lieu de la zone de champs de camera pour détruire les instances de bullet.
Alors je n’arrive pas à identifier ou ce situe le problème, la tourelle est activé (variable automaticSteering==true) pendant 10 seconde via un timer, pendant ces 10 seconde des instance de" bullet " son créer puis détruit lorsqu'ils sortent du champ de la caméra, au bout des 10 seconde, je remet la variable "automaticSteering=false", réinitialise le timer à 10 seconde et remet l'angle Z de la tourelle dans ça position initiale mais, les derniers bullet instanciés ne sont pas détruits .
Si vous avez des idées, merci
Sinon je vais voir si cela change quelque chose en utilisant un timer au lieu de la zone de champs de camera pour détruire les instances de bullet.
Code : Tout sélectionner
using UnityEngine;
using System.Collections;
public class ScriptTourelle : MonoBehaviour
{
public float speed=10f;
public float fireRate=0.2f;
public float timeLimit=10f;
public GameObject player;
public GameObject bullet;//Prefab bullet
public GameObject bulletPosition;//Objet empty
private bool locked;
private float inputY;
private float nextFire;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
locked=player.GetComponent<ScriptPlayer>().automaticSteering;
if (locked == true)
{
inputY = Input.GetAxis ("Vertical");
transform.Rotate (0, 0, (Time.deltaTime * inputY) * speed);
if((Input.GetKeyDown("space"))&&(Time.time>nextFire))
{
nextFire=Time.time+fireRate;
GameObject shot=(GameObject)Instantiate(bullet, bulletPosition.transform.position, Quaternion.identity);
shot.transform.rotation=transform.rotation;
}
timeLimit-=Time.deltaTime;
}
if(timeLimit<0)
{
player.GetComponent<ScriptPlayer>().automaticSteering=false;
transform.rotation=Quaternion.Euler(0,0,-90);
timeLimit=10f;
}
}
}
Code : Tout sélectionner
using UnityEngine;
using System.Collections;
public class ScriptWeaponSecondaire : MonoBehaviour
{
public float speed=0.5f;
private float power;
private Vector2 max;
// Use this for initialization
void Start ()
{
power = 0.0f;
max= Camera.main.ViewportToWorldPoint(new Vector2(1,1));
}
// Update is called once per frame
void Update ()
{
power = speed * Time.deltaTime;
transform.Translate( Vector3.up * power);
if ((transform.position.x > max.x) || (transform.position.y > max.y))
{
Destroy(gameObject);
}
}
}
Re: [Shooter 2D]Tirer en fonction d'une rotation [C#][RESOLU]
Le DestroyGameObjet est beaucoup plus simple à utiliser.Sinon je vais voir si cela change quelque chose en utilisant un timer au lieu de la zone de champs de camera pour détruire les instances de bullet.
Code : Tout sélectionner
// Kills the game object in 5 seconds after loading the object
Destroy (gameObject, 5);
Re: [Shooter 2D]Tirer en fonction d'une rotation [C#][RESOLU]
Génial!, tellement simple que j'ai même pas pensé à aller voir l'API.
Merci à toi.
Je viens de testé en plaçant le destroy() dans Update() ou start(), c'est le même comportement, point de vue optimisation c'est quoi le mieux et pourquoi?
Merci à toi.
Je viens de testé en plaçant le destroy() dans Update() ou start(), c'est le même comportement, point de vue optimisation c'est quoi le mieux et pourquoi?
Re: [Shooter 2D]Tirer en fonction d'une rotation [C#][RESOLU]
Bonjour,
La fonction Start() est appelée une seule fois au début du script.
Les fonctions Update et FixedUpdate sont appelées en boucle tout au long de la vie du script.
La Doc Unity 3d répond à la question : ICI
L'utilisation du système est que tout ce qui est initialisation et qui ne se fait qu'une fois, se fait dans le Start. Tout ce qui est mise à jour, calcules ou gestion de l'objet au cours du temps se fait dans l'une des deux boucles.
L'information "L'objet doit se détruire dans x secondes" doit se faire au début et n'a pas à être modifiée plus tard, donc la logique et donc l'optimisation du code font que Destroy() doit être placée dans le Start().
La fonction Start() est appelée une seule fois au début du script.
Les fonctions Update et FixedUpdate sont appelées en boucle tout au long de la vie du script.
La Doc Unity 3d répond à la question : ICI
L'utilisation du système est que tout ce qui est initialisation et qui ne se fait qu'une fois, se fait dans le Start. Tout ce qui est mise à jour, calcules ou gestion de l'objet au cours du temps se fait dans l'une des deux boucles.
L'information "L'objet doit se détruire dans x secondes" doit se faire au début et n'a pas à être modifiée plus tard, donc la logique et donc l'optimisation du code font que Destroy() doit être placée dans le Start().
Re: [Shooter 2D]Tirer en fonction d'une rotation [C#][RESOLU]
Nouveau script pour une arme latéral qui apparaît lors d'une collision avec un objet "bonus".
Cette arme est composé de deux autre éléments du vaisseau (un droite et un gauche) qui viennent s'arrimées et à une durée de vie de 45
sec.
Cette arme est composé de deux autre éléments du vaisseau (un droite et un gauche) qui viennent s'arrimées et à une durée de vie de 45
sec.
Code : Tout sélectionner
using UnityEngine;
using System.Collections;
public class ScriptweaponLateralRight : MonoBehaviour
{
public float speedStowage = 0.5f;//vitesse d'arrimage
public float speed;//vitesse de deplacement
public float timeLife=15f;//duree de vie
public Vector2 directionStowage = new Vector2 (0, -1).normalized;//vecteur de direction
public GameObject player;//objet cible pour arrimage
public GameObject bullet;//prefab bullet
public GameObject bulletPosition;//ObjetEmpty respawn bullet
public float fireRate=0.2f;//cadence de tir
public bool isRight=true;//weapon element droite ou gauche
private bool isStowage=false;//arrimage reussi
private float inputX;//input axe X
private float inputY;//input axe Y
private float nextFire;//tir suivant
// Use this for initialization
void Start ()
{
Destroy (gameObject,timeLife);
}
// Update is called once per frame
void Update ()
{
if(isStowage==false)//si pas d'arrimage
{
isStowage=Stowage (directionStowage, isRight);//arrimage en cour
}
if(isStowage==true)//si arrimage
{
//capture des touches pour le deplacement
inputX = Input.GetAxisRaw("Horizontal");
inputY = Input.GetAxisRaw("Vertical");
//Vector de mise à jour
Vector2 direction = new Vector2 (inputX, inputY).normalized;
//move en fonction de l'element droite ou gauche
move(direction, isRight);
//gestion du tir
if((Input.GetKeyDown("space"))&&(Time.time>nextFire))
{
nextFire=Time.time+fireRate;
GameObject shot=(GameObject)Instantiate(bullet);
shot.transform.position=bulletPosition.transform.position;
}
}
}
private bool Stowage(Vector2 directionStowage, bool right)
{
bool locked = false;
if (right == true)//si weaponLateralRight
{
Vector2 pos = transform.position;
Vector2 posCible = player.transform.position;
pos += directionStowage * speedStowage * Time.deltaTime;
if (pos.y - 0.06f > posCible.y + 0.105f)
{
transform.position = pos;
locked = false;
}
else
{
locked = true;
}
}
if (right == false)//si weaponLateralLeft
{
Vector2 pos = transform.position;
Vector2 posCible = player.transform.position;
pos -= directionStowage * speedStowage * Time.deltaTime;
if (pos.y + 0.06f < posCible.y - 0.105f)
{
transform.position = pos;
locked = false;
}
else
{
locked = true;
}
}
return locked;
}
void move(Vector2 direction, bool right)
{
if (right == true)//si weaponLateralRight
{
Vector2 min = Camera.main.ViewportToWorldPoint (new Vector2 (0, 0));
Vector2 max = Camera.main.ViewportToWorldPoint (new Vector2 (1, 1));
max.x = max.x - 0.265f;
min.x = min.x + 0.265f;
max.y = max.y - 0.06f;
min.y = min.y + 0.39f;
Vector2 pos = transform.position;
pos += direction * speed * Time.deltaTime;
pos.x = Mathf.Clamp (pos.x, min.x, max.x);
pos.y = Mathf.Clamp (pos.y, min.y, max.y);
transform.position = pos;
}
if (right == false)//si weaponLateralLeft
{
Vector2 min = Camera.main.ViewportToWorldPoint (new Vector2 (0, 0));
Vector2 max = Camera.main.ViewportToWorldPoint (new Vector2 (1, 1));
max.x = max.x - 0.265f;
min.x = min.x + 0.265f;
max.y = max.y - 0.39f;
min.y = min.y + 0.06f;
Vector2 pos = transform.position;
pos += direction * speed * Time.deltaTime;
pos.x = Mathf.Clamp (pos.x, min.x, max.x);
pos.y = Mathf.Clamp (pos.y, min.y, max.y);
transform.position = pos;
}
}
}