With ncurses, the screen will be 80x24, so with ncursesw, using UTF-8 full-width code, with a square character, about 40 years ago of 40x24, PET, MZ-80, CBM-3032, I tried to rewrite the game of PC-8001 (which also has 80x25 mode). I modified the game "Raging Robots" a little and made it "Maneaters".
I will leave the detailed explanation of ncursesw to other articles (Oioi), but I will post the program list. Since there is no explanation of ncursesw, I wrote the comments as carefully as possible. You will see how to use minimal ncursesw.
In addition, the operation check was ubuntu18.04 and Debian stretch (9.6). Binary packages can be found on GitHub. https://github.com/fygar256/maneaters/blob/master/maneaters_1.3-1_amd64.deb
~~ Ubuntu libncursesw5 (6.1-1ubuntu1.18.04) and Debian libncursesw5 (6.0 + 20161126-1 + deb9u2) have bugs, even if you use vim, certain symbols in utf-8 will show It may be chipped or the character width may not be large enough. For example, ~~ "◯" (large circle: not a machine-dependent character, ambiguous width) causes a problem, but "O" (capital letter O, full-width) does not cause a problem. Regarding this, siracamus pointed out, "For Ubuntu terminals, it may be solved by changing" Ambiguous width character: "in the compatibility tab of the terminal's Preferences setting to" full-width ". So, when I tried it, it was certainly solved in the game (prototype).
~~ But vim didn't work properly. ~~
It seems that the East Asian Ambiguous font is displayed in half-width or full-width depending on the locale. Again, according to siracamus's information, vim worked fine with : set ambiwidth = double
.
The terminal and vim settings have been resolved with the above two points. Thank you, siracamus.
This program is made without using ambiguous fonts.
Before compiling
sudo apt-get install libncursesw5-dev
Please install the package as. How to compile
cc maneaters.c -o maneaters -lncursesw
is.
maneaters.c
//
//Nostalgic, CBM-Character games like 3032
//Realized with ncursesw.
// Maneaters. Ver 1.3
//
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//To use ncursesw, the following two header files
#include <ncursesw/ncurses.h>
#include <locale.h>
//The characters to be output are defined as constants.
#define ENEMY "O"
#define PLAYER "@"
#define ROCK "#"
#define CRASH "X"
#define SPACE " "
//Definition of a function that generates a random number from 0 to x.
#define rnd(x) (rand()%x)
int enemyl[40]; //Flag of whether the enemy is alive
int enemyx[40]; //Enemy x coordinate
int enemyy[40]; //Enemy y coordinate
int rockl[320]; //Flag of whether there is a rock
int rockx[320]; //Rock x coordinate
int rocky[320]; //Rock y coordinate
int enemymax=12; //Number of first enemies
int rockmax=120; //Number of first rocks
int playerx,playery; //Player coordinates
int h,w; //Screen height,width
int xsize,ysize; //Game screen size.
//80x25 screen, square full-width UTF with monospaced font-8
//And I'm using it
//Here, xsize is 40.
int gamestat; //Game status: 0 Now playing
//1 lose
//3 win
/*
*When the player moves
*Determining if you hit something
*Return value;1: Collision 0: Nothing
*/
int check_player_crash() {
//
//Judgment of whether or not it hit the enemy
//
for(int i=0;i<enemymax;i++) {
if((enemyl[i]==1)&&(playerx==enemyx[i]) && (playery==enemyy[i]))
return(1);
}
//
//Determining if you hit a rock
//
for(int i=0;i<rockmax;i++) {
if((rockl[i]==1)&&(playerx==rockx[i]) && (playery==rocky[i]))
return(1);
}
return(0);
}
/*
*A function that displays characters on the screen.
*Since it is handled in full-width units,
*The x coordinate is doubled.
*/
int putchara(int x,int y,char *str){
move(y,x*2);
addstr(str);
}
/*
*Game initialization
*/
int init_game() {
int i;
clear(); //Clear screen
gamestat=0; //Initialize game state
//Take the seed of the random number from time and initialize it.
srand((unsigned)time(NULL));
//
//Put a rock.
//The 0th is to avoid collision between the player and the enemy
//Place the dummy in the center of the screen. Therefore, the number of rocks is
// rockmax-It becomes 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;
}
//Place the enemy so that it does not hit the rock.
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++;
}
}
//Place the player in the center of the screen.
putchara(playerx=xsize/2,playery=ysize/2,PLAYER);
}
/*
*Move the enemies
*/
void move_maneaters() {
int dx,dy;
int x,y;
for(int i=0;i<enemymax;i++) {
if (enemyl[i]==0) //Skip if the enemy is dead
continue;
//
//Ask for the difference to chase the player
//
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;
//Disappear the enemy at your current position
putchara(enemyx[i],enemyy[i],SPACE);
//Find the coordinates of where the enemy moved
x=enemyx[i]+dx,y=enemyy[i]+dy;
//
//Check for collisions between enemies
//
for(int j=0;j<enemymax;j++) {
if ((i!=j)&&(enemyl[j]==1) && (x==enemyx[j]) && (y==enemyy[j])) {
enemyl[i]=0; //Lower the flag that the enemy is alive.
}
}
//
//Collision check with rocks
//
for(int j=0;j<rockmax;j++) {
if ((rockl[j]==1)&&(x==rockx[j]) && (y==rocky[j])) { //Did you hit the rock?
rockl[j]=enemyl[i]=0;
putchara(x,y,SPACE); //Erase the rock
}
}
enemyx[i]=x,enemyy[i]=y; //Take the enemy one step further
if (enemyl[i]) //Is the enemy alive?
putchara(enemyx[i],enemyy[i],ENEMY); //Draw the enemy
//
//Check if it collided with the player
//
if ((x==playerx) && (y==playery))
gamestat=1; //If you collide, you lose
}
}
//
//Game main loop
//
int main_game() {
int f,dx,dy;
while(1) {
/*
*Player processing
*/
switch(getch()) { //Player key input and acquisition of movement direction
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;
}
//Does the player go off the screen?
if (((playerx+dx)>=0) && ((playerx+dx)<xsize) &&
((playery+dy)>=0) && ((playery+dy)<ysize)) {
putchara(playerx,playery,SPACE); //Take the player one step further.
playerx+=dx;
playery+=dy;
putchara(playerx,playery,PLAYER);
//When the player hits a rock or an enemy, the game is over.
if (check_player_crash()) {
gamestat=1;
return(0);
}
}
/*
*Enemy processing
*/
move_maneaters();
if (gamestat!=0) return(0);
/*
*Win if the man-eater is annihilated
*/
f=0;
for(int j=0;j<enemymax;j++)
f|=enemyl[j];
if (f==0) {
gamestat=3;
return(0);
}
}
}
/*
*A function that asks if you want to play again
*Return value; 0: No 1: Yes
*/
int tryagainp() {
printw("Try Again? [y/n]");
while(1) {
switch(getch()) {
case 'n': return(0);
case 'y': return(1);
default: continue;
}
}
}
/*
*Game description screen
*
*/
void instruction() {
clear(); //Clear screen
printw("Maneaters Ver 1.3\n"); //Print to stdscr with 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(); //Waiting for one-character key input.
}
//
//Game description screen and main loop loop
//
void play_game() {
while(1) {
instruction(); //Call the game description screen.
init_game(); //Game initialization
main_game(); //Game main loop
if (gamestat==1) { //Player loses
putchara(playerx,playery,CRASH);
move(0,0);
printw("You Lose ");
}
if (gamestat==3) { //Player wins
move(0,0);
printw("You Win!! ");
}
if (tryagainp()==0) return; //Return if not replayed.
}
}
/*
*main function
*/
int main() {
setlocale( LC_ALL,"" ); //UTF with ncursesw-To use 8
// LC_Set ALL.
initscr(); //Screen initialization
noecho(); //Remove keyboard echo
curs_set(0); //Hide the cursor.
getmaxyx(stdscr,h,w); //Screen size, h,Store in w
//Usually 80x25
xsize=w/2; //Find the screen size to use in the game.
ysize=h; //Find the Y size of the screen used in the game.
play_game(); //Run the game.
endwin(); //Close the screen.
exit(0); //Finished.
}
Recommended Posts