[LINUX] Nostalgique, reproduisons un jeu de personnages comme CBM-3032 avec ncursesw.

Avec ncurses, l'écran sera de 80x24, donc avec ncursesw, en utilisant le code pleine largeur de UTF-8, avec un caractère carré, il y a environ 40 ans de 40x24, PET, MZ-80, CBM-3032, J'ai essayé de réécrire le jeu de PC-8001 (qui a également le mode 80x25). J'ai un peu modifié le jeu "Raging Robots" et l'ai fait "Maneaters".

Je laisserai l'explication détaillée de ncursesw à d'autres articles (Oioi), mais je posterai la liste des programmes. Puisqu'il n'y a aucune explication de ncursesw, j'ai écrit les commentaires aussi soigneusement que possible. Vous verrez comment utiliser les ncurses minimum w.

De plus, la vérification de l'opération était ubuntu18.04 et Debian stretch (9.6). Le package binaire peut être trouvé sur GitHub. https://github.com/fygar256/maneaters/blob/master/maneaters_1.3-1_amd64.deb

~~ Ubuntu libncursesw5 (6.1-1ubuntu1.18.04) et Debian libncursesw5 (6.0 + 20161126-1 + deb9u2) ont un bogue, et même si vous utilisez vim, il est affiché avec un certain symbole de utf-8. Il peut être ébréché ou la largeur des caractères peut ne pas être assez grande. Par exemple, ~~ "◯" (grand cercle: pas un caractère dépendant du modèle, largeur ambiguë) pose un problème, mais "O" (lettre supérieure O, pleine largeur) ne pose pas de problème. A ce propos, siracamus a souligné, "Pour les terminaux Ubuntu, il peut être résolu en changeant" Caractère de largeur ambigu: "dans l'onglet de compatibilité du paramètre Préférences du terminal sur" Pleine largeur ". Donc, quand je l'ai essayé, cela a certainement été résolu dans le jeu (prototype).

~~ Mais vim ne fonctionnait pas correctement. ~~ La police ambiguë (ambiguë d'Asie de l'Est) semble être affichée en demi-largeur ou pleine largeur selon les paramètres régionaux. Encore une fois, selon les informations de siracamus, vim fonctionnait bien avec : set ambiwidth = double.

Les paramètres du terminal et de vim ont été résolus avec les deux points ci-dessus. Merci, siracamus.

Ce programme est fait sans utiliser de polices ambiguës.

Avant de compiler

sudo apt-get install libncursesw5-dev

Veuillez installer le package en tant que. Comment compiler

cc maneaters.c -o maneaters -lncursesw

est.

maneaters.c


//
//Nostalgique, CBM-Jeux de personnages comme 3032
//Réalisé avec ncursesw.
//  Maneaters. Ver 1.3
//

#include  <stdio.h>
#include  <stdlib.h>
#include  <time.h>

//Pour utiliser ncursesw, les deux fichiers d'en-tête suivants
#include  <ncursesw/ncurses.h>
#include  <locale.h>

//Les caractères à afficher sont définis comme des constantes.
#define ENEMY   "O"
#define PLAYER  "@"
#define ROCK    "#"
#define CRASH   "X"
#define SPACE   " "

//Définition d'une fonction qui génère un nombre aléatoire de 0 à x.
#define rnd(x) (rand()%x)

int enemyl[40];   //Drapeau indiquant si l'ennemi est vivant
int enemyx[40];   //Coordonnées ennemies x
int enemyy[40];   //Ennemi et coordonnée

int rockl[320];   //Drapeau s'il y a un rocher
int rockx[320];   //Coordonnées Rock X
int rocky[320];   //Coordonnée Rock y

int enemymax=12;  //Nombre de premiers ennemis

int rockmax=120;  //Nombre de premières roches

int playerx,playery;  //Coordonnées du joueur

int h,w;              //Hauteur de l'écran,width

int xsize,ysize;      //Taille de l'écran de jeu.
                      //Écran 80x25, UTF carré pleine largeur avec police de largeur égale-8
                      //Et je l'utilise
                      //Ici, xsize vaut 40.

int gamestat;         //Statut du jeu: 0 Lecture en cours
                      //1 perdre
                      //3 victoire

/*
 *Quand le joueur bouge
 *Déterminer si vous frappez quelque chose
 *Valeur de retour;1: Collision 0: Rien
 */
int check_player_crash() {
  //
  //Déterminer si vous frappez un ennemi
  //
  for(int i=0;i<enemymax;i++) {
    if((enemyl[i]==1)&&(playerx==enemyx[i]) && (playery==enemyy[i]))
      return(1);
    }
  //
  //Jugement si oui ou non il a heurté un rocher
  //
  for(int i=0;i<rockmax;i++) {
    if((rockl[i]==1)&&(playerx==rockx[i]) && (playery==rocky[i]))
      return(1);
    }
  return(0);
}

/*
 *Une fonction qui affiche des caractères à l'écran.
 *Puisqu'il est traité en unités pleine largeur
 *La coordonnée x est doublée.
 */
int putchara(int x,int y,char *str){
  move(y,x*2);
  addstr(str);
}

/*
 *Initialisation du jeu
 */
int init_game() {
  int i;
  clear();            //Écran propre

  gamestat=0;         //Initialiser l'état du jeu

  //Prenez la graine du nombre aléatoire du temps et initialisez-la.
  srand((unsigned)time(NULL));

  //
  //Placez une pierre.
  //Le 0 est d'éviter la collision entre le joueur et l'ennemi
  //Placez le mannequin au centre de l'écran. Par conséquent, le nombre de roches est
  //  rockmax-Cela devient 1.
  // 
  rockx[0]=xsize/2;
  rocky[0]=ysize/2;
  rockl[0]=0;
  for(i=1;i<rockmax;i++) {
    putchara(rockx[i]=rnd(xsize),rocky[i]=rnd(ysize),ROCK);
    rockl[i]=1;
    }

  //Placez l'ennemi de manière à ce qu'il ne touche pas le rocher.
  i=0;
  while(i<enemymax) {
    int ex,ey,f;
    ex = rnd(xsize);
    ey = rnd(ysize);
    f = 0;
    for(int j=0;j<rockmax;j++) {
      if ((ex==rockx[j])&&(ey==rocky[j]))
        f=f|1;
      }
    if (f==0) {
      putchara(enemyx[i]=ex,enemyy[i]=ey,ENEMY);
      enemyl[i]=1;
      i++;
      }
    }

  //Placez le lecteur au centre de l'écran.
  putchara(playerx=xsize/2,playery=ysize/2,PLAYER);

}

/*
 *Déplacer les ennemis
 */
void  move_maneaters() {
  int dx,dy;
  int x,y;

  for(int i=0;i<enemymax;i++) {
    if (enemyl[i]==0)   //Passer si l'ennemi est mort
          continue;
    //
    //Demandez la différence pour chasser le joueur
    //
    dx=0,dy=0;
    if (enemyx[i]<playerx) dx=1;
    if (enemyx[i]>playerx) dx=-1;
    if (enemyy[i]<playery) dy=1;
    if (enemyy[i]>playery) dy=-1;

    //Disparaître l'ennemi dans la position actuelle
    putchara(enemyx[i],enemyy[i],SPACE);

    //Trouvez les coordonnées de l'endroit où l'ennemi s'est déplacé
    x=enemyx[i]+dx,y=enemyy[i]+dy;

    //
    //Vérification des collisions entre ennemis
    //
    for(int j=0;j<enemymax;j++) {
      if ((i!=j)&&(enemyl[j]==1) && (x==enemyx[j]) && (y==enemyy[j])) {
          enemyl[i]=0;          //Abaissez le drapeau indiquant que l'ennemi est vivant.
          }
      }

    //
    //Contrôle de collision avec des roches
    //
    for(int j=0;j<rockmax;j++) {
      if ((rockl[j]==1)&&(x==rockx[j]) && (y==rocky[j])) { //As-tu frappé le rocher
        rockl[j]=enemyl[i]=0;
        putchara(x,y,SPACE);  //Effacez le rocher
        }
      }

    enemyx[i]=x,enemyy[i]=y;  //Emmenez l'ennemi un peu plus loin
    if (enemyl[i])    //Les ennemis sont-ils vivants?
      putchara(enemyx[i],enemyy[i],ENEMY);  //Dessiner un ennemi

    //
    //Vérifiez s'il est entré en collision avec le lecteur
    //
    if ((x==playerx) && (y==playery))
        gamestat=1;     //Si vous vous heurtez, vous perdez
    }

}

//
//Boucle principale du jeu
//
int main_game() {
  int f,dx,dy;
  while(1) {

/*
 *Traitement des joueurs
 */
  switch(getch()) {     //Entrée clé du joueur et acquisition de la direction du mouvement
    case  '7': dx=-1,dy=-1; break;
    case  '8': dx= 0,dy=-1; break;
    case  '9': dx= 1,dy=-1; break;
    case  'u': case  '4': dx=-1,dy=0; break;
    case  'i': case  '5': dx= 0,dy=0; break;
    case  'o': case  '6': dx= 1,dy=0; break;
    case  'j': case  '1': dx=-1,dy=1; break;
    case  'k': case  '2': dx= 0,dy=1; break;
    case  'l': case  '3': dx= 1,dy=1; break;
    default:
      continue;
    }

    //Le joueur sort-il de l'écran?
    if (((playerx+dx)>=0) && ((playerx+dx)<xsize) &&
        ((playery+dy)>=0) && ((playery+dy)<ysize)) {

      putchara(playerx,playery,SPACE);  //Amenez le joueur un peu plus loin.
      playerx+=dx;
      playery+=dy;
      putchara(playerx,playery,PLAYER);

      //Lorsque le joueur frappe un rocher ou un ennemi, le jeu est terminé.
      if (check_player_crash()) {
              gamestat=1;
              return(0);
            }
      }
    /*
     *Traitement ennemi
     */
    move_maneaters();
    if (gamestat!=0) return(0);

    /*
     *Gagnez si le mangeur d'hommes est anéanti
     */
    f=0;
    for(int j=0;j<enemymax;j++)
      f|=enemyl[j];
    if (f==0) {
      gamestat=3;
      return(0);
      }
  }
}
    
/*
 *Une fonction qui vous demande si vous souhaitez rejouer
 *Valeur de retour; 0: Non 1: Oui
 */
int tryagainp() {
  printw("Try Again? [y/n]");
  while(1) {
    switch(getch()) {
      case  'n': return(0);
      case  'y': return(1);
      default: continue;
      }
    }
}

/*
 *Écran de description du jeu
 *
 */
void  instruction() {
    clear();      //Écran propre

    printw("Maneaters Ver 1.3\n"); //Imprimez sur stdscr avec printw.

    printw("Mission : kill all maneaters to survive!\n");
    printw("%s -- Maneater, chase player step by step.\n",ENEMY);
    printw("%s -- Rock, die maneaters and player when touched. \n",ROCK);
    printw("%s -- Player, control for maneaters to crash to rock and survive!\n",PLAYER);
    printw("\n");
    printw("Key control:             Tenkey:     \n");
    printw(" 7  8  9            7 8  9   \n");
    printw("  ↖ ↑  ↗                 ↖ ↑  ↗     \n");
    printw("u← i →o             4← 5→ 6   \n");
    printw("  ↙ ↓  ↘                 ↙ ↓  ↘     \n");
    printw(" j  k   l           1  2  3   \n");
    printw("\n");
    printw(" 'i' and '5' move maneater and don't move player.\n");
    printw("             Good Luck\n");
    printw("hit key\n");

    getch();    //En attente de la saisie d'une touche à un caractère.
  }

//
//Écran de description du jeu et boucle principale
//
void  play_game() {
  while(1) {

    instruction();    //Appelez l'écran de description du jeu.

    init_game();      //Initialisation du jeu

    main_game();      //Boucle principale du jeu

    if (gamestat==1) {  //Le joueur perd
      putchara(playerx,playery,CRASH);
      move(0,0);
      printw("You Lose ");
      }

    if (gamestat==3) {  //Le joueur gagne
      move(0,0);
      printw("You Win!! ");
      }

    if (tryagainp()==0) return; //Revenir si non rejoué.
    }
}
/*
 *fonction principale
 */
int main() {
  setlocale( LC_ALL,"" ); //UTF avec ncursesw-Pour utiliser 8
                          // LC_Mettre tous.

  initscr();              //Initialisation de l'écran

  noecho();               //Désactiver l'écho du clavier

  curs_set(0);            //Cachez le curseur.

  getmaxyx(stdscr,h,w);   //Taille de l'écran, h,Magasin dans w
                          //Habituellement 80x25

  xsize=w/2;              //Trouvez la taille d'écran utilisée dans le jeu.

  ysize=h;                //Trouvez la taille Y de l'écran utilisé dans le jeu.

  play_game();            //Lancez le jeu.

  endwin();               //Fermez l'écran.

  exit(0);                //Fini.
}


Recommended Posts

Nostalgique, reproduisons un jeu de personnages comme CBM-3032 avec ncursesw.
Essayez de créer un jeu simple avec Python 3 et iPhone
Sentons-nous comme un chercheur en matériaux avec l'apprentissage automatique
J'ai fait un jeu de puzzle (comme) avec Tkinter of Python
Sentons-nous comme un chercheur de matériaux avec python [Introduction à pymatgen]
Faisons une interface graphique avec python.
Faisons une rupture de bloc avec wxPython
Zura fait comme un jeu de la vie
Faisons un graphe avec python! !!
Faisons un spacon avec xCAT
Jouez comme une application Web avec ipywidgets
J'ai fait un compteur de caractères avec Python
Créons un groupe gratuit avec Python
Raclons un site dynamique avec Docker
Faisons la voix lentement avec Python
Faisons un langage simple avec PLY 1
J'ai fait un jeu de vie avec Numpy
Créez un framework Web avec Python! (1)
Faisons une IA à trois yeux avec Pylearn 2
Analysons la machine de jeu rétro chinoise
Lire le fichier de données de caractères avec numpy
Faisons un bot Twitter avec Python!
J'ai fait un jeu rogue-like avec Python
Créez un framework Web avec Python! (2)