Bonjour,
je suis confronté à l'un des problèmes mystiques qu'on ne rencontre qu'en C++.
J'ai créé une classe Animation. Après plusieurs lignes de code, je compile le tout et le compilateur hurle:
Citation : Compilateur
main.cpp:68: error: request for member `jouer' in `anim', which is of non-class type `Animation ()(Timer, int, int)'
J'ai relu plusieurs fois mon code mais impossible de trouver l'erreur.
Animation.h
#ifndef TIMER
#define TIMER
#include <SDL/SDL.h>
class Timer
{
private:
//moment de lancement
int ticks_debut;
//statut du timer
bool en_marche;
public:
//constructeur
Timer();
//mise en route et arrêt
void marche();
void arret();
//vérification du statut
bool get_en_marche();
//renvoie le temps écoulé
int get_ticks();
};
#endif
Ce qu'il faudrait voir c'est la déclaration de la variable anim. Visiblement, tu l'as déclaré comme une fonction et non comme une instance de classe. C'est assez classique comme erreur avec le constructeur par défaut, mais là avec des paramètres je ne vois pas trop comment tu as pu te débrouiller
On ne voit pas la déclaration de la classe Animation... C'est normal, ou la classe de "Animation.h" ne porte pas le bon nom
si on est dans le 2eme cas, le problème vient du fait que du définit une fonction jouer() dans la classe anime alors qu'elle n'est pas présente dans la déclaration de la classe
c'est parce qu'il a déclaré son objet dans le main comme ça:
Animation anim();
tu ne dois pas mettre de parenthèse s'il n'y a aucun argument.
Sinon, je crois que tu t'es trompé de header ?!?
Laurent, peut-etre que dans le header il y a des paramètre par defaut, donc il instancie sans paramêtre ?
Animation anim(Timer timer, int nbre_frames=2, int delai = 1000);
Sinon j'ai bien fait include "Animation.cpp" dans le main.
Pour Animation.h je me suis trompé c'est ça
#ifndef ANIMATION
#define ANIMATION
#include "Timer.h"
class Animation
{
private:
Timer timer;
int nbre_frames;
int delai_frame;
bool en_cours;
//frame actuelle
int frame;
public:
//constructeur
Animation::Animation(Timer timer, int nbre_frames, int delai_frame);
//statut de l'animation
bool get_en_cours();
//mise en route et arrêt
void jouer();
void stop();
//renvoie le numéro de la frame actuelle
int get_frame();
};
#endif
Plus besoin d'envoyer un timer dans la déclaration, j'ai utilisé le constructeur par défaut de la classe Timer dans le constructeur de Animation.
Et enfin la fonction get_frame:
int Animation::get_frame()
{
//si on a lancé l'animation
if(en_cours == true)
{
//et si c'est l'heure
if(timer.get_ticks() >= delai_frame)
{
//on augmente ou on réinitialise la frame
if(frame >= nbre_frames - 1 )
{
frame = 0;
}
else
{
frame++;
}
//on remet le timer à 0
timer.marche();
return frame;
}
}
//on renvoie 0 si l'animation n'est pas lancée
return 0;
}
Mais (parce qu'il y a un mais ), cette fonction pose problème: en la regardant, on voit qu'elle retourne 0 si on a pas lancé l'animation (à l'aide de la méthode jouer()).
Dans mon main, j'ai mis ce bout de code qui permet d'afficher avec un alternance de 1 seconde un écran blanc et noir, histoire de tester Animation:
switch(anim.get_frame())
{
case 0:
SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 255, 255, 255));
break;
case 1:
SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 0, 0, 0));
break;
//sinon c'est un bug
default:
exit(EXIT_FAILURE);
break;
}
SDL_Flip(ecran);
Quand je compile, l'écran reste blanc (la frame reste bloquée à 0).
Ce qui est encore plus bizarre, c'est que quand je fais return 1 à la fin de get_frame(), l'écran reste noir (frame reste à 1).
J'ai donc pensé que l'on entrait jamais dans le if(en_cours).
Pourtant j'ai bien fait Anim.jouer(); pour mettre à true en_cours.
Ou alors peut être est-ce du à une mauvaise déclaration du timer dans le constructeur:
Faut il faire timer(Timer()) ?
Je ne vois pas de faute grossière dans mes méthodes mais après tout je suis un Zér0
Sans conviction, je dirai que c'est là dedans que tu ne passes pas :
if(timer.get_ticks() >= delai_frame)
Mets une trace pour t'en convaincre.
Et, juste par souci de lisibilité du code (mais ça n'engage que moi), tu devrais plutôt faire quelque chose comme ça :
int Animation::get_frame()
{
//si on a lancé l'animation et si c'est l'heure
if(en_cours && timer.get_ticks() >= delai_frame)
{
//on augmente ou on réinitialise la frame
if(frame >= nbre_frames - 1 )
{
frame = 0;
}
else
{
frame++;
}
//on remet le timer à 0
timer.marche();
return frame;
}
else
return false;
//on renvoie false (ce qui n'est pas zéro) si l'animation n'est pas lancée
}
On pourrait voir ton Timer.cpp s'il te plait ? Plus particulièrement le get_ticks() ?
Y'a jamais de problème mystique en informatique (enfin c'est pas tout à fait vrai). Mais quand il y a un souci, il vient souvent de ce qui se trouve entre la chaise et l'écran ^_^.
int Animation::get_frame()
{
//si on a lancé l'animation et si c'est l'heure
if( en_cours && timer.get_ticks() >= delai_frame )
{
//on augmente ou on réinitialise la frame
if( frame >= nbre_frames - 1 )
{
frame = 0;
}
else
{
frame++;
}
//on remet le timer à 0
timer.marche();
return frame;
}
else
return false; //on renvoie false (ce qui n'est pas zéro) si l'animation n'est pas lancée
}
Impossible ! Ce n'est pas du PHP. Il est possible de retourner 0 ou -1 car il faut renvoyer un int.
Impossible ! Ce n'est pas du PHP. Il est possible de retourner 0 ou -1 car il faut renvoyer un int.
Ouais, erreur d'inattention enfin c'était juste pour lui préciser de ne pas retourner zéro pour une frame invalide (un -1 serait peut-être plus approprié). Cela dit, si je suis d'accord avec toi sur le principe de la présentation du code, je suis moins d'accord quand tu dis que c'est impossible. Même GCC ne braille pas si tu lui présentes un code du type ci-dessous. Il me semble qu'il caste le bool comme 1 ou 0.
#include <cstdlib>
#include <iostream>
using namespace std;
int foo(int bar)
{
if(bar<=0)
return false;
else
return bar;
}
int main(int argc, char *argv[])
{
int number = -1;
if(foo(number))
cout << "foo : ";
else
cout << "nan : ";
cout << foo(number) << endl;
system("PAUSE");
return EXIT_SUCCESS;
}
Citation : MatteX
Le else ne change rien. Mais je suis en accord avec l'élimination des "== true".
C'est pareil que ce soit l'un ou l'autre, c'est juste pour avoir un code plus propre. Le else sert à éviter de jouer sur le "break" du return.
Glaucos => Ton main, c'est le même que précédemment ? Je croyais que tu avais utilisé un switch ? Je testerai ce soir avec ce main là.
Impossible ! Ce n'est pas du PHP. Il est possible de retourner 0 ou -1 car il faut renvoyer un int.
Ouais, erreur d'inattention enfin c'était juste pour lui préciser de ne pas retourner zéro pour une frame invalide (un -1 serait peut-être plus approprié). Cela dit, si je suis d'accord avec toi sur le principe de la présentation du code, je suis moins d'accord quand tu dis que c'est impossible. Même GCC ne braille pas si tu lui présentes un code du type ci-dessous. Il me semble qu'il caste le bool comme 1 ou 0.
Oui, car il y a transtypage implicite. Mais comme tu le dis : « Il me semble qu'il caste le bool comme 1 ou 0 » alors je crois que ca ne change rien au fait qu'il doit retournée une valeur qui ne serait pas retournée lors du succès de la fonction. Il est même illogique de retourner une valeur booléenne dans une fonction qui retourne un int. En plus, tu ne sais même pas ce que va retourner false. Solution possible : faire des fonctions solides avec gestion d'exception.
Citation : UnKnOwN DrAgOoN
Citation : MatteX
Le else ne change rien. Mais je suis en accord avec l'élimination des "== true".
C'est pareil que ce soit l'un ou l'autre, c'est juste pour avoir un code plus propre. Le else sert à éviter de jouer sur le "break" du return.
Le return va sauter qu'il y ai un else ou non. Personnellement, je pense que c'est plus lisible sans le else. Mais encore, dans ce genre de situation je rechercherais les causes d'erreurs possibles et les gérerais avec les exception seulement aux endroits potentiellement dangereux et pas à tout les retours de fonctions (qui ne sont, d'ailleur, pas validés).
alors je crois que ca ne change rien au fait qu'il doit retournée une valeur qui ne serait pas retournée lors du succès de la fonction.
Ca je sais pas, faudrait tester avec un ===, mais techniquement vu que c'est un int, ça ne change rien.
Citation : MatteX
Le return va sauter qu'il y ai un else ou non. Personnellement, je pense que c'est plus lisible sans le else. Mais encore, dans ce genre de situation je rechercherais les causes d'erreurs possibles et les gérerais avec les exception seulement aux endroits potentiellement dangereux et pas à tout les retours de fonctions (qui ne sont, d'ailleur, pas validés).
Pour moi, c'est moins propre. Ca ressemble plus à un break qu'autre chose dans le sens où la fonction "ne s'achève pas". M'enfin, les goûts et les couleurs...
Pour le code, je compile de suite, sorry j'avais un peu zappé, j'édite une fois le test effectué.
Edit : J'ai compris et je me demande même pourquoi je ne l'ai pas remarqué plus tôt...après avoir épuré ton code dans tous les sens (selon ma vision des choses :p), je ne comprenais toujours pas ce qui clochait, en fait c'est simple :
int Animation::get_frame()
{
//si on a lancé l'animation et si c'est l'heure
if(en_cours && timer.get_ticks() >= delai_frame)
{
//on augmente ou on réinitialise la frame
if(frame >= nbre_frames - 1 )
{
frame = 0;
}
else
{
frame++;
}
//on remet le timer à 0
timer.marche();
return frame;
}
else
return false;
//on renvoie false (ce qui n'est pas zéro) si l'animation n'est pas lancée
}
Observes ton code. A chaque fois que tu appelles la méthode get_frame, tu augmentes d'une frame puis tu la retournes, en conséquence de quoi, logiquement parlant, ton test n'est jamais vrai. get_frame(), lorsque la frame vaut 1, te renverra 0. Alors que toi tu testes si elle vaut 1. Idem pour le zéro. Cela vient du fait que ton get_frame ne fait pas que lire la frame en cours. Comme solution, je pense qu'un truc tout con du style :
Je viens de tester, ça tourne (selon ton code), maintenant d'après moi, y'a pas mal d'épurations à faire niveau algo'...enfin bon, je te laisse bricoler. En rapport avec ce qui a été dit plus haut, en cas d'erreur, je te suggère de retourner -1, sinon ton code ne marchera toujours pas (entre les frames il affichera du blanc) et donc de rajouter une condition :
Merci infiniment UnKnOwN DrAgOoN maintenant je connais la cause de mon problème mystique qui ne l'est plus
Citation : UnKnOwN DrAgOoN
Je viens de tester, ça tourne (selon ton code), maintenant d'après moi, y'a pas mal d'épurations à faire niveau algo'...enfin bon, je te laisse bricoler. En rapport avec ce qui a été dit plus haut, en cas d'erreur, je te suggère de retourner -1, sinon ton code ne marchera toujours pas (entre les frames il affichera du blanc) et donc de rajouter une condition :
Oui en effet il m'affiche une frame blanche longue contre un flash rouge etc...
Incompréhensiblement il m'affiche presque toujours du bleu foncé (il rentre dans le else)
1-je ne vois pas comment il pourrait rentrer dans le else sauf si l'animation n'est pas lancée (cf. anim.get_frame())
2-j'ai pourtant apporté les améliorations que tu m'as donné:
int Animation::get_frame()
{
//si on a lancé l'animation et si c'est l'heure
if(en_cours && timer.get_ticks() >= delai_frame)
{
//on augmente ou on réinitialise la frame
if(frame >= nbre_frames - 1 )
{
frame = 0;
}
else
{
frame++;
}
//on remet le timer à 0
timer.marche();
return frame;
}
//retourne -1 en cas d'erreur
else
{
return -1;
}
}
Peux-tu poster ton code ? Ai-je oublié quelquechose dans le mien ?
Pas besoin de poster mon code, ton nouveau souci est très simple à comprendre :
Citation : Glaucos
1-je ne vois pas comment il pourrait rentrer dans le else sauf si l'animation n'est pas lancée (cf. anim.get_frame())
int frame_en_cours = anim.get_frame();
Celle ligne est dans ton while (ce qui est logique) : à chaque passage dans le while, tu réclames une frame. Le problème est que, si jamais ce n'est pas l'heure, tu retournes une erreur (en référence à ta méthode get_frame). Autrement dit, tant que ce n'est pas encore l'heure, ton get_frame te renvoie -1, et donc ton while affiche du bleu foncé. Pour palier ce problème, le plus simple est de ne rien afficher si jamais la frame reçue est < 0. Mets ton fameux else en commentaire et tu n'auras plus de souci.
Après, tu peux éventuellement faire un système du genre "si erreur alors afficher la dernière frame valide reçue", mais cela implique que tu sauvegarde à chaque while la valeur de la frame de sorte à ce qu'elle soit accessible au while suivant *espère être clair*.
Au lieu de sauvegarder la frame dans frame_precedente on pouvait modifier get_frame pour qu'elle retourne la frame précédente si ce n'est pas l'heure.
get_frame() finale:
int Animation::get_frame()
{
//si on a lancé l'animation et si c'est l'heure
if(en_cours && timer.get_ticks() >= delai_frame)
{
//on augmente ou on réinitialise la frame
if(frame >= nbre_frames - 1 )
{
frame = 0;
}
else
{
frame++;
}
//on remet le timer à 0
timer.marche();
}
//on retourne la nouvelle frame ou la dernière frame si ce n'est pas l'heure
return frame;
}
Ce code marche incroyablement bien ! Et coté utilisateur rien de plus simple il suffit de donner le nombre de frames et le delai et c'est bon !
P.S: j'ai diminué de 1 la frame à chaque fois (anim.get_frame) pour facilité un blit sur feuille de sprites (les tableaux commençant à zéro).
alors je crois que ca ne change rien au fait qu'il doit retournée une valeur qui ne serait pas retournée lors du succès de la fonction.
Ca je sais pas, faudrait tester avec un ===, mais techniquement vu que c'est un int, ça ne change rien.
Geee, '===' ça n'existe pas en C++.
Sinon bravo pour la solution, Glaucos faut mettre le sujet en 'résolu' maintenant.
problème mystique
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
* Un wrapper C++ pour sqlite * Une alternative a boost units