7

我正在制作一个基于 ASCII 的游戏,而且无论我看到哪里,人们都在说要使用 MSDN 中的 Console.Write(),如果你使用的是 Windows,这很不错,但我不是。

因此,我试图在 C 中编写一个函数或一组函数,可以在两个屏幕缓冲区之间交替,并将它们写入屏幕,类似于手册页的样子,以及 pico、vim 和emacs。

我有缓冲区的工作,并找到了一个名为 0verkill 的旧 ASCII linux 游戏,它使用 C 和 putchar() 将每个字符放在屏幕上,但是我所有重新创建它的尝试都会导致文本的连续流动,而不是窗口大小的静态文本面板。我真的不想使用任何像 curses 这样的外部库(因为这会降低可移植性),并且如果可能的话,我想保持 ansi 标准。

谢谢!

4

4 回答 4

5

我真的不想使用任何像curses这样的外部库(因为这会降低可移植性)

什么?像 curses 和 ncurses 这样的库旨在使这种东西便携,因为......

并希望尽可能保持 ansi 标准。

...对于您想要的,没有 ANSI 标准(至少对于 C)。每个操作系统都以不同的方式实现这种行为,所以如果你想要一种可移植的方式来实现它,你需要使用一个库。老实说,我讨厌必须为没有移植 ncurses 的系统进行开发。想象一下没有它你将无法使用的所有程序。

于 2009-10-09T04:40:20.283 回答
4

我认为您正在寻找的是清除屏幕的ANSI 控制字符。ESC[2J您可以在任何状态更改后调用它来“刷新”控制台屏幕。

请参阅此页面以了解其余内容。使用这些代码,您可以在控制台上定义颜色和格式(间距、对齐、缩进等)。

于 2009-10-09T04:48:12.000 回答
3

有一个 ANSI 标准 X3.64,还有描述 DEC VT100 终端的 ISO/IEC 6429。该标准描述了兼容终端模拟器将识别的颜色和光标定位的某些转义序列,基本上所有 X 终端,但在 Windows 上不一定(可能您需要用户加载ansi.sys)。正是这最后一个丑陋的不一致说明了为什么你应该使用抽象出这些细节的 ncurses。

于 2009-10-09T04:51:22.803 回答
3

一个示例头文件和源文件,说明了从应用程序中抽象诅咒的方法。收集灰尘;15年前写的。买者自负。

诅咒mu.h

/***************************************************************************
 *                                                                          
 *  DO NOT CHANGE ANYTHING BETWEEN THIS LINE AND THE NEXT LINE THAT HAS THE 
 *  WORDS "KLAATU BARRATA NIKTO" ON IT                                      
 *                                                                          
 ***************************************************************************/
#ifndef X__CURSEMU__H                                                        
#define X__CURSEMU__H                                                        

#include <stdio.h>

#ifdef  linux
#define _POSIX_VERSION
#endif                

#ifndef _POSIX_VERSION
#include <sgtty.h>    
#define  USE_OLD_TTY  
#include <sys/ioctl.h>
#undef  USE_OLD_TTY   

#ifndef  CBREAK
#define CBREAK RAW
#endif            

#if !defined(sun) && !defined(sequent) && !defined(hpux) && \
    !defined(_AIX) && !defined(aix)                          
#include <strings.h>                                         
#define strchr index                                         
#else                                                        
#include <string.h>                                          
#endif                                                       
#else                                                        
#include <string.h>                                          
#include <termios.h>                                         
#endif                                                       

#include <errno.h>
#include <sys/types.h>
#include <pwd.h>      
#include <sys/time.h> 
#include <sys/file.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>     
#include <signal.h>    

/* Keep looking ... */

int _tty_ch;

#ifdef  _POSIX_VERSION
struct termios _tty;  
tcflag_t _res_iflg,   
    _res_lflg;        

#define cbreak()(_tty.c_lflag&=~ICANON, \
  tcsetattr( _tty_ch, TCSANOW, &_tty ))  

#define noecho()(_tty.c_lflag &= ~(ECHO|ICRNL), \
  tcsetattr( _tty_ch, TCSADRAIN, &_tty ))        

#define savetty()((void) tcgetattr(_tty_ch, &_tty), \
  _res_iflg = _tty.c_iflag, _res_lflg = _tty.c_lflag )

#define resetty()(_tty.c_iflag = _res_iflg, _tty.c_lflag = _res_lflg,\
  (void) tcsetattr(_tty_ch, TCSADRAIN, &_tty))                        

#define erasechar()(_tty.c_cc[VERASE])
#else                                 
struct sgttyb _tty;                   
int _res_flg;                         

#define cbreak()(_tty.sg_flags|=CBREAK, ioctl(_tty_ch, TIOCSETP, &_tty))

#define noecho()(_tty.sg_flags &= ~(ECHO|CRMOD), \
  ioctl( _tty_ch, TIOCSETP, &_tty ))              

#define savetty()((void) ioctl(_tty_ch, TIOCGETP, &_tty), \
  _res_flg = _tty.sg_flags )                               

#define resetty()(_tty.sg_flags = _res_flg, \
  (void) ioctl(_tty_ch, TIOCSETP, &_tty))    
#define erasechar()(_tty.sg_erase)           
#endif                                       

/* KLAATU BARRATA NIKTO */

#define  TERMCAP_LENGTH 1024

struct CtrlSeq
{             
  char termcap[ TERMCAP_LENGTH ];

  int numRows, numCols;

  /*  These pointers are indexes into the termcap buffer, and represent the
   *  control sequences neccessary to send to the terminal window to perform
   *  their appropriately named feature.
   */
  char *highlight,
       *endMode,            /* End highlight mode, and other modes. */
       *clearScr,
       *clearEol,
       *scrollRegion,
       *moveCursor,
       *deleteRow,
       *insertRow,
       *saveCursor,         /* Save the current cursor position */
       *restoreCursor;      /* Restore the saved cursor position */

  int dumbTerm,             /* 1 if the terminal is a dumb terminal */
      flush;                /* 1 if the emulation should flush stdout */
};

struct CtrlSeq ctrlSeq;

#define DEFAULT_COLS    80
#define DEFAULT_ROWS    24

void ce_flush( int toSet );
void ce_puts( char *str );
void ce_gotoRowCol( int row, int col );

void ce_writeStrRowCol( char *theText, int row, int col );
void ce_writeStr( char *theText );
void ce_writeCharRowCol( char theChar, int row, int col );
void ce_writeChar( char theChar );

void ce_clearScreen( void );
void ce_clearEol( void );

void ce_highlight( int on );
void ce_scrollRegion( int row1, int row2 );
void ce_deleteRow( int row );
void ce_insertRow( int row );
void ce_saveCursor( void );
void ce_restoreCursor( void );

int ce_getRows( void );
int ce_getCols( void );

#endif

诅咒mu.c

#include "cursemu.h"

int putchar_x( int c )
{                     
  return( putchar( c ) );
}                        

/*  Returns 0 on success, -1 on error
 */                                  
int ce_startCurses( void )           
{                                    
  char *ptr,                         
       tempBuff[ 1024 ];             
  int  result = 0;                   

  if( (ptr = (char *)getenv( "TERM" )) != NULL )
    result = tgetent( tempBuff, ptr );          
  else                                          
    result = tgetent( tempBuff, "vt100" );      

  if( result < 1 )
  {               
    perror( "FATAL Error: No termcap entry found (even tried vt100)!\n" );
    return( -1 );                                                         
  }                                                                       

  ptr = ctrlSeq.termcap;

  if( (ctrlSeq.numCols = tgetnum( "co" )) == -1 )
    ctrlSeq.numCols = DEFAULT_COLS;              
  if( (ctrlSeq.numRows = tgetnum( "li" )) == -1 )
    ctrlSeq.numRows = DEFAULT_ROWS;              

  if( (ctrlSeq.moveCursor = (char *)tgetstr( "cm", &ptr )) == NULL )
    ctrlSeq.moveCursor = (char *)tgetstr( "cl", &ptr );             
  if( (ctrlSeq.highlight = (char *)tgetstr( "mr", &ptr )) == NULL ) 
    ctrlSeq.highlight = (char *)tgetstr( "md", &ptr );              

  ctrlSeq.endMode       = (char *)tgetstr( "me", &ptr );
  ctrlSeq.clearEol      = (char *)tgetstr( "ce", &ptr );
  ctrlSeq.clearScr      = (char *)tgetstr( "cl", &ptr );
  ctrlSeq.scrollRegion  = (char *)tgetstr( "cs", &ptr );
  ctrlSeq.deleteRow     = (char *)tgetstr( "dl", &ptr );
  ctrlSeq.insertRow     = (char *)tgetstr( "al", &ptr );
  ctrlSeq.saveCursor    = (char *)tgetstr( "sc", &ptr );
  ctrlSeq.restoreCursor = (char *)tgetstr( "rc", &ptr );

  ctrlSeq.dumbTerm = (ctrlSeq.moveCursor == NULL) ||
                     (ctrlSeq.scrollRegion == NULL) ||
                     (ctrlSeq.saveCursor == NULL) ||  
                     (ctrlSeq.restoreCursor == NULL) ||
                     (ctrlSeq.clearEol == NULL);       

  ctrlSeq.flush = 1;

  if( !ctrlSeq.dumbTerm )
  {                      
    if( (_tty_ch = open( "/dev/tty", O_RDWR, 0 ) ) == -1 )
      _tty_ch = 0;                                        

    savetty();
    cbreak(); 
    noecho(); 
    return( 0 );
  }             

  return( -1 );
}              

int ce_endCurses( void )
{                       
  ce_scrollRegion( -1, -1 );
  ce_gotoRowCol( ce_getRows() - 1, 0 );
  resetty();                           
}                                      

void ce_flush( int toSet )
{                         
  ctrlSeq.flush = toSet;  

  if( toSet == 1 )
    fflush( stdout );
}                    

void ce_puts( char *str )
{                        
  tputs( str, 0, putchar_x );

  if( ctrlSeq.flush )
    fflush( stdout );
}                    

void ce_gotoRowCol( int row, int col )
{                                     
  if( row > ctrlSeq.numRows )         
    row = ctrlSeq.numRows;            
  if( col > ctrlSeq.numCols )         
    col = ctrlSeq.numCols;            

  ce_puts( (char *)tgoto( ctrlSeq.moveCursor, col, row ) );
}                                                          

void ce_writeStrRowCol( char *theText, int row, int col )
{                                                        
  ce_flush( 0 );                                         
  ce_gotoRowCol( row, col );                             
  ce_writeStr( theText );                                
  ce_flush( 1 );                                         
}                                                        

void ce_writeStr( char *theText )
{                                
  ce_flush( 0 );                 
  printf( "%s", theText );       
  ce_flush( 1 );                 
}                                

void ce_writeCharRowCol( char theChar, int row, int col )
{                                                        
  ce_flush( 0 );                                         
  ce_gotoRowCol( row, col );                             
  ce_writeChar( theChar );                               
  ce_flush( 1 );                                         
}                                                        

void ce_writeChar( char theChar )
{                                
  ce_flush( 0 );                 
  printf( "%c", theChar );       
  ce_flush( 1 );                 
}                                

void ce_clearScreen( void )
{                          
  ce_puts( ctrlSeq.clearScr );
}

void ce_clearEol( void )
{
  ce_puts( ctrlSeq.clearEol );
}

void ce_highlight( int on )
{
  if( on == 0 )
    ce_puts( ctrlSeq.endMode );
  else
    ce_puts( ctrlSeq.highlight );
}

void ce_scrollRegion( int row1, int row2 )
{
  ce_puts( (char *)tgoto( ctrlSeq.scrollRegion, row1, row2 ) );
}

void ce_deleteRow( int row )
{
  ce_gotoRowCol( row, 0 );
  ce_puts( ctrlSeq.deleteRow );
}

void ce_insertRow( int row )
{
  ce_gotoRowCol( row, 0 );
  ce_puts( ctrlSeq.insertRow );
}

void ce_saveCursor( void )
{
  ce_puts( ctrlSeq.saveCursor );
}

void ce_restoreCursor( void )
{
  ce_puts( ctrlSeq.restoreCursor );
}

int ce_getRows( void )
{
  return( ctrlSeq.numRows );
}

int ce_getCols( void )
{
  return( ctrlSeq.numCols );
}

编译

要求:

gcc -o cursemu.o -lcurses -ltermcap
于 2009-10-09T05:16:39.500 回答