Mes lacunes

Pour les scripts écrits en Javascript (UnityScript). :!: Obsolète :!:
Règles du forum
Merci de respecter la NOMENCLATURE suivante pour vos TITRES de messages :

Commencez par le niveau de vos scripts
DB = Débutant
MY = Moyen
CF = Confirmé

Puis le domaine d'application
-RS = Réseau
-AL = Algorithmie

Exemple :

[DB-RS] Mouvement perso multijoueur
splint
Messages : 9
Inscription : 24 Jan 2016 23:12

Mes lacunes

Message par splint » 25 Jan 2016 11:33

Bonjour à toutes et à tous

Je me lance dans un petit projet personnel , mon premier petit jeux, qui est un grand défit pour mes compétences actuel sous unity. J'ai volontairement placé la barre assez haute pour un débutant en programmation (que je suis^^).
On pourrai penser que c'est le piège habituel, pas assez de connaissance et finira par abandonner :/
Peut être bien (même si je sais être très obstiner lol) mais cela n'a guère d'importance. Je compte pas détrôner EA, mon projet n'es pas dans un but lucratif mais uniquement dans le but d'acquérir de nouvelle connaissance et de m'améliorer en programmation sous unity.
C'est là que vous intervenez :P
Je veux pas avoir des scripts tout fait, je veux comprendre et pouvoir refaire sous d'autre projet sans venir systématiquement vous embêtez :)
Avant de parler du petit projet, de où j'en suis et de vous demandez un peu de votre temps (oui je post pas juste pour vous dire ce que je fais, j'ai actuellement besoin de vos lumières^^) je vais vous dire où j'en suis dans mes connaissances :

programmation sous java Script (considérer moi comme un débutant)
je suis une formation a distance d’analyste informatique (qui j'espère vas booster mes connaissances en programmation)
quelque base solide en 3d (cinema 4d, zbrush)

Voila, il es temps de parler du projet et d'en venir au fait. Désolé si je traîne un peu, j'adore le suspens lol

il s'agit d'un jeu d'aventure/stratégie vu à la 3eme personne. Le héro devra détruire des villages ennemis (une dizaine pour finir le jeu) mais devra également créer son propre village subissant des assauts sur ce dernier. Entre chaque village le joueur devra traversé un chemin infesté d'ennemi. (Inspirer d'un jeu très connu mais revue a ma façon ^^) Voila l'idée principal, comme je vous disais j'ai placé la barre haute pour une première tentative ;-)

J'en viens donc au moment où je vous embêtes :oops:
Je suis entrain de scripter l’évolution des bâtiments du village. J'ai créer une variable tableau dans laquelle j'ai placé les gameObjects des différents level. Par contre je n'arrive pas utiliser "intelligemment" ce tableau. Pour mes test je n'ai que 3 level mais imaginons que je procède un nombre impressionnant... Je pensais pouvoir identifier avec le raycast à quel index je suis et pouvoir passer à l'index suivant mais j'ai lamentablement échoué :(
Mon script fonctionne tel quel mais j'aurai voulu savoir s'il y avait la possibilité de passer par les index ou d''optimiser le script. Voila le script :

Code : Tout sélectionner

var batimentDef : GameObject[];
var hit : RaycastHit;
var ray : Ray;
var target : Transform;
var argent : int = 2000;



function Start () {
	 Instantiate(batimentDef[0], target.position, target.rotation);


}

function Update () {
	if(Input.GetMouseButtonDown(0)){
		 ray = Camera.main.ScreenPointToRay(Input.mousePosition);
		if(Physics.Raycast(ray, hit)){
			if(hit.transform.tag == "Batiment"){
				BatimentUP();
			}
		}
	}
}

function BatimentUP(){
	//var ray : Ray = Camera.main.ScreenPointToRay(Input.mousePosition);
		if(Physics.Raycast(ray, hit)){
				if(hit.transform.name == "bat lvl1(Clone)" && argent >= 150){
					Instantiate(batimentDef[1] , target.position, target.rotation);
					argent -= 150;
					Destroy(hit.transform.gameObject);
				}
	 			if( hit.transform.name =="bat lvl2(Clone)" && argent >= 300){
					Instantiate(batimentDef[2] , target.position, target.rotation);
					argent -= 300;
					Destroy(hit.transform.gameObject);
				}
				if(hit.transform.name == "bat lvl3(Clone)" && argent >= 600){
					Instantiate(batimentDef[3] , target.position, target.rotation);
					argent -= 600;
					Destroy(hit.transform.gameObject);
				}
		}
}

Merci à vous

Avatar de l’utilisateur
boubouk50
ModoGenereux
ModoGenereux
Messages : 6265
Inscription : 28 Avr 2014 11:57
Localisation : Saint-Didier-en-Bresse (71)

Re: Mes lacunes

Message par boubouk50 » 25 Jan 2016 11:53

Pour "optimiser", disons plutôt dynamiser ton code, tu devrais passer par des tableaux, des Lists, des énumérations et des classes qui te permettent de gérer un nombre non-défini d'entrées.
Par exemple, au lieu d'avoir en dur, 150, 300 et 600 pour l'argent dans ton compte et le nom batiment, tu peux avoir une classe BatimentEnnemi qui contient ses informations: argent minimum / lvl du batiment / batiment à instancier, puis un tableau contenant ses classes là que tu parcours à chaque RayCast tant que tu n'as pas trouvé le bon.
L'idée est à chaque fois penser générique et paramétrable plutôt que statique et fixé.
"Ce n'est pas en améliorant la bougie, que l'on a inventé l'ampoule, c'est en marchant longtemps."
Nétiquette du forum
Savoir faire une recherche
Apprendre la programmation

Avatar de l’utilisateur
Titan
Messages : 582
Inscription : 12 Sep 2011 13:54
Contact :

Re: Mes lacunes

Message par Titan » 25 Jan 2016 13:51

Pour complété ce que dit boubouk, un bon moyen de savoir si ta conception est bonne, c'est de voir si tu a besoin de dupliquer du code. à chaque fois que tu a envie de copier/coller un bloc, il faut s’arrêter, prendre du recul, factoriser, etc. C'est pas une lacune spécifique aux amateurs, j'ai quelques rigolo dans mon open-space qui pensent savoir coder mais qui passent leurs journées à taper des switch, quand je repasse derrière pour ajouter un type d'éléments ou un comportement commun j'ai des envie de meurtre.

Dans ton exemple de code tu a dupliquer trois fois ta logique, tu pourrais mettre dans un premier temps ta logique d'amélioration dans une fonction:

Code : Tout sélectionner

if(hit.transform.name == "bat lvl1(Clone)" && argent >= 150)
   Upgrade(150, batimentDef[0], hit.transform.gameObject);
if( hit.transform.name =="bat lvl2(Clone)" && argent >= 300)
   Upgrade(300, batimentDef[1], hit.transform.gameObject);
if(hit.transform.name == "bat lvl3(Clone)" && argent >= 600)
   Upgrade(600, batimentDef[2], hit.transform.gameObject);

fonction Upgrade(price : int, newPrefab : GameObject, oldObject : GameObject)
{
   Instantiate(newPrefab, oldObject.transform.position, oldObject.transform.rotation);
   argent -= price;
   Destroy(oldObject);
}
C'est un début pour te montrer la logique de factorisation à suivre, mais c'est loin d'être suffisant: la condition est encore dupliquer pour chaque bâtiment à cause du nom et du prix. C'est pour ça que tu a besoin d'une classe bâtiment qui centralise cette information comme le suggère boubouk.

d'autres "rull of dumb" que je te donne en vrac pour que tu sache, non pas corrigé tes erreurs de conception, mais au moins les détecté:
1) jamais de copier/coller => factoring
2) jamais de comparaison de string => enum
3) jamais de valeurs harcoder dans tes fonctions => variables
4) jamais de valeurs définit à plusieurs endroit => si la variable n'est pas accessible il faut revoir la conception
5) dans unity, jamais utiliser l'inspector pour câbler des éléments sur la scène
____________________________________________
Hop Boy

splint
Messages : 9
Inscription : 24 Jan 2016 23:12

Re: Mes lacunes

Message par splint » 25 Jan 2016 14:27

Merci à vous deux pour ces réponses très constructive.
Je vais revoir le code en respectant vos indications. Encore un grand merci :)

splint
Messages : 9
Inscription : 24 Jan 2016 23:12

Re: Mes lacunes

Message par splint » 27 Jan 2016 21:43

Bonsoir :)

Alors me revoilà toujours sur le même script :/ ça fait des jours que je me tape la tête par terre pour comprendre comment fonctionne une classe :x
Après plusieurs tentative dans tous les sens je penses être sur le bon chemin mais voilà un truc m'échappe et je me tourne vers vous :lol:
J'essaie de suivre les instructions de titan et de boubouk en pensant générique, j'ai donc repris le code à zéro et pour l'instant la notion du Raycast n'est pas encore mis en place. Comme mon expérience ne me le permet pas, je préfère construire le script petit bout par petit bout pour mieux contrôler ce qui va pas... :)

Voila donc à quoi ressemble ma class

Code : Tout sélectionner

class BatimentEnnemi extends MonoBehaviour{

	var nomBatiment : String;
	var level : int;
	var price : int;

	public function BatimentEnnemi(nom : String, lvl : int){
		nomBatiment = nom;
		level = lvl; // au départ cette variable n'existait pas, j'ai tester comme ça pour voir si l'incrémentation avait lieu
	}

	public function build(obj :GameObject, target : Transform){
		Instantiate(obj, target.position, target.rotation);

	}

	public function Upgrade(newBat : GameObject[], oldBat : GameObject){
		Instantiate(newBat[level], oldBat.transform.position, oldBat.transform.rotation);
		level ++; // Incrémentation ne fonctionne pas
	
	}

}
Le problème c'est que dans la fonction "Upgrade" ma variable level ne s'incrémente pas et même dans l'inspector je ne peux pas changer sa valeur :|

je vous met le code de ce qui se passe en update

Code : Tout sélectionner

function Update (){
	var tour : BatimentEnnemi = new BatimentEnnemi("tour", 1);
	checkLvl = tour.level; 

	if(Input.GetMouseButtonDown(0)){
		tour.build(bat1, target);
	}
	if(Input.GetMouseButtonDown(1)){
		tour.Upgrade(listBat, bat1);
	}

}
Si ça peut servir :lol:

Code : Tout sélectionner

var bat1 : GameObject;
var target : Transform;
var listBat : GameObject[];
var checkLvl : int;
J'ai bien essayé de mettre la listBat de batiment à instancier dans la class BatimentEnnemi, le souci est qu'elle n’apparaît pas dans l'inspecteur, du coup aucun moyen de remplir les préfabs dedans. Alors j'ai opter pour une déclaration hors class

Avatar de l’utilisateur
Titan
Messages : 582
Inscription : 12 Sep 2011 13:54
Contact :

Re: Mes lacunes

Message par Titan » 28 Jan 2016 12:59

Ça commence à ressembler à quelque chose au lieu d'avoir une string "Tour" tu doit définir un enum, c'est plus optimisé, et ça évite les erreurs.
Les erreurs d’exécution ("pourquoi ça fait rien quand je lance ?") sont beaucoup plus pénible à régler que les erreurs de compilation ("ficher xxx.js, ligne 38, TypeBatiment.Touur inconnu").

Code : Tout sélectionner

enum TypeBatiment
{
   Tour,
   Maison
}

var type : TypeBatiment;

function Xxx()
{
   type =  TypeBatiment.Tour;
}
Il faut que tu face attention aux erreurs dans la console. Quand tu fait un new sur ta classe BatimentEnnemi qui hérite de MonoBehaviour, il doit te dire que c'est pas bien, et vu que c'est dans un Update il a du te le dire beaucoup. Les MonoBehaviour sont des classes particulière dans Unity qui doivent être attaché à des GameObject et qu'on ne doit instancier qu'avec des AddComponent(). Vu ton code, ce n'es pas ce que tu souhaite. Il existe les "ScriptableObject" dont tu pourrai hériter pour arriver à une conception proche de ce que tu imagine mais on va éviter d'introduire encore une nouvelle notion, alors je vais te proposer une conception qui s'en passe.

attache ton script BatimentEnnemi à un nouveau gameobject, puis crée un prefab avec ce Gameobject. ça va être ton bâtiment! l'autre script, qui sert a faire des test en appelant des fonctions de ton bâtiment ne doit posséder aucune variable en dehors du prefab de ton bâtiment.ton BatimentEnnemi doit avoir listbat, qui contient les différent "rendu" de ton bâtiment à différent niveaux (si j'ai bien compris). ton upgrade peut instancier un gameobject child à ta position (n'oublie pas de détruire l'ancien!). par contre ton batiment ne doit pas avoir de fonciton "build", l'instantiate doit être fait directement dans ton script de test. différencie bien la variable du prefab de ton batiment (bat1) de la variable du bâtiment instancié (tour), et n'oublie pas qu'une variable local (dans update) est détruite quand tu sors de la fonciton, tu doit donc déclarer un membre "private var tour : BatimentEnnemi" pour qu'il reste (pour ça que ton checklevel reste à 0). enfin Instantiate va te retourner un gameobject, garde le dans une variable local puis fait un getComponent dessus pour retrouver ton script BatimentEnnemi.

Je sais pas si je suis clair, j'ai l'impression qu'il y a trop de chose à expliquer pour que ça se face par un forum. En tout cas bonne chance, tu va dans la bonne direction, mais il faudrait peut être commencer par un Pong pour bien comprendre la relation entre GameObject (entité du jeu sur lesquelles tu attache tes script), Monobehaviour (tout les script que tu fait en héritent par défaut), Instanciate (crée un gameobject), GetComponent (retrouve l'un de tes script sur un gameobject), AddComponent (ajoute un nouveau script à un gameobject, sert très peu vu qu'on instancie toujours des prefab). bien comprendre la notion de classe et d'héritage, de scope de variable, de new (à bannir pour tes script). ne pas confondre les prefab et les instances de ta scéne (au sens unity) qui sont pourtant tout deux des instances de class GameObject (au sens programmation).
tu doit apprendre la programmation en même temps qu'unity, c'est ça qui fait que tu te retrouve perdu.
____________________________________________
Hop Boy

splint
Messages : 9
Inscription : 24 Jan 2016 23:12

Re: Mes lacunes

Message par splint » 28 Jan 2016 13:30

Merci pour ta réponse Titan.
Tu as tout à fait compris ce que je veux faire et je te remercie vraiment d'avoir pris le temps de détailler la procédure.
Je voulais éviter pour je ne sais quel raison d'attacher un script au prefab :lol:
Je vais pouvoir me pencher dessus et revoir les anciens tutos "basique" pour me rafraîchir la mémoire.
J'éspère pouvoir revenir avec un script fonctionnel à te montrer. Juste pour te montrer que tes explications ne sont pas inutile :-D

splint
Messages : 9
Inscription : 24 Jan 2016 23:12

Re: Mes lacunes

Message par splint » 08 Fév 2016 18:15

Un petit coucou pour te dire titan que ça y es, grâce a toi j'ai réussi. J'ai intégré le script au projet et sa fonctionne. Merci et peut être à plus tard si je bloque sur autre chose :lol:
Merci pour ce que tu fais et bonne continuation.

splint
Messages : 9
Inscription : 24 Jan 2016 23:12

Re: Mes lacunes

Message par splint » 18 Fév 2016 09:56

Bonjour, me revoilà :oops:

Alors cette fois rien a voir avec mes bâtiments, le projet suis sont cours et on arrive aux troupes qui attaquent nos fameux bâtiments. Jusque là aucun souci. Mes troupes s'en prennent au bâtiment le plus proche, selon le type de bâtiment en priorité.

Mais (et oui il y a un mais lol) lorsque je place un mur (obstacle) mes troupes pas très débrouillard foncent dedans. Ces pas un gros problème en soit puis que ces murs sont justement là pour empêcher les troupes d'atteindre leur cible et les troupes pourront se mettre à leur taper dessus pour les casser :-D
Ce qui me dérange si je passe ainsi avec mon code actuel, et je suis sur que vous l'avez deveniez ;-) est que deux troupes visant la même cible à un mètre d'écart vont me faire deux trous dans le mur au lieu de ce concentrer sur le même endroit du mur.
Egalement, si la cible n'est pas entouré complètement mais que la petite troupe ne faisant qu'avancer sur un vecteur directeur fonce dans le mur et va l'attaquer. Or il es plus rapide de ce décaler d'un mètre que de vouloir casser le mur.
J'espère être assez clair dans mes explications...
Du coup j'ai quand même bûcher un peu avant de venir vous voir, comme d'habitude :) mais là je dirais en vue de mes connaissances j'ai trois solutions et je ne sais pas vraiment vers laquelle m'orienté. pouvez vous donc m'aider encore un peu voir même beaucoup :lol:

1ere possibilité : j'ai tanté une approche avec les NavMesh (au passage je trouve les renseignements sur le navmesh assez réduit donc dur dur). Dans un premier temps ma semblé la solution idéal. si j'entoure pas complètement le bat, les troupes vont dans le passage (ou trou), et si j'entoure la cible/batiment completement, ma troupe allait buter sur le mur. Parfait, un petit

Code : Tout sélectionner

OnCollisionEnter 
et op le mur saute :) je test et oui !! tout content je pousse le test, j'entoure la cible/batiment, et j'entoure encore le tout et là :( ma troupe n'avance plus, ne sais plus quoi faire, j'ai voulu pousser le code en disant que si le chemin est invalid tu t'en prend au mur mais comme je le disais vu mon niveau je trouve à ce niveau rien.

2eme possibilité : coder en "bourrin" et créer une cible temporaire lorsqu'un mur est détruit. J'ai pas tester mais ça peut le faire, ayant un trou et du coup une target instancier, les autres troupes se trouvant dans un certain rayon empreinte la target... Le souci je penses est pour les cibles/batiments pas complétement entouré. Ca ne changerai pas la donne (pas testé mais il me semble)

3eme possibilité : pas faire de mur :mdr1:

Dernière petite chose, mes troupes se poussent entre elles (du à leur rigidbody, charactercontroller ou encore navmesh) comment désactivé cette collision entre elles mais uniquement entre elles car j'en ai besoin pour la collision contre les murs.

Je suis désolé de vous faire tant de lecture à chaque fois que je viens. Pour tant je n'ais pas rêvé de faire romancier mais c'est vrai que je vous fais une tartine à chaque fois. J’essaierai d'être moins bavard à l'avenir et merci d'avance pour votre aide.
A bientot

Avatar de l’utilisateur
Titan
Messages : 582
Inscription : 12 Sep 2011 13:54
Contact :

Re: Mes lacunes

Message par Titan » 20 Fév 2016 14:59

Pour désactiver la collision entre tes unité, il suffit de leur donner un layer qui ne collide pas avec lui même.
Pour tes problémes d'IA tu est sur la bonne voie, continu de faire des test avec le navmesh pour bien le maitriser ensuite ta procédure doit être:
- d'abord recherche de chemin
- si pas de chemin j'attaque le mur qui à le moins de vie
- si aucun n'a perdu de vie, attaque celui qui est sur le chemin

Les IA ça se développe plus facilement avec des behavior tree, il y a plusieurs plugin sur le store (Behavior Designer, Behave 2 for Unity, Behavior Bricks Lite, ...) mais c'est pas du tout indispensable.

edit: tu peut aussi regarder la collaborative diffusion pour ton probléme
____________________________________________
Hop Boy

Verrouillé

Revenir vers « (Js) Javascript »