一、背景
马上过春节了,在家闲暇时间,看到了别人php写的一个命令行游戏,直接拿过来用c语音实现了一下哈。
二、相关知识
1、CLI颜色打印方法,使用printf控制就行,以下从网上收录了一些常用的颜色码:
打印格式为:
printf("\033[字背景颜色;字体颜色m字符串\033[0m");
40: 黑 30: 黑 41: 红 31: 红 42: 绿 32: 绿 43: 黄 33: 黄 44: 蓝 34: 蓝 45: 紫 35: 紫 46: 深绿 36: 深绿 47: 白色 37: 白色
2、CLI的控制码
\033[0m 关闭所有属性 \033[1m 设置高亮度 \03[4m 下划线 \033[5m 闪烁 \033[7m 反显 \033[8m 消隐 \033[30m -- \033[37m 设置前景色 \033[40m -- \033[47m 设置背景色 \033[nA 光标上移n行 \03[nB 光标下移n行 \033[nC 光标右移n行 \033[nD 光标左移n行 \033[y;xH设置光标位置 \033[2J 清屏 \033[K 清除从光标到行尾的内容 \033[s 保存光标位置 \033[u 恢复光标位置 \033[?25l 隐藏光标 \33[?25h 显示光标
三、实现
其实这个idea是网上参考的哦,梳理出来思路如下:
1、定义血量HP、魔法MP,勇士发动攻击则需要消耗MP;
2、战斗方式为回合制,勇士和恶龙分别选择攻击方式进行PK;
基础定义:
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <string.h>
#define HP_MAX 20 #define MP_MAX 20 #define LOGGREEN(fmt, args...) printf("\033[40;32m"fmt"\033[0m", ##args); #define LOGYELLOW(fmt, args...) printf("\033[40;33m"fmt"\033[0m", ##args); #define LOGBLUE(fmt, args...) printf("\033[40;36m"fmt"\033[0m", ##args); #define LOGD(fmt, args...); printf(fmt, ##args); #define LOGX(fmt, args...); offset += snprintf(msg + offset, 1000 - offset, fmt, ##args); static char msg[1000] = {0}; static int offset = 0;
typedef enum cmd_enum { ROLE_YOU = 1, ROLE_DRAGON = 2, CMD_ENUM_MIN = '0', CMD_ENUM_ATTACK = '1', CMD_ENUM_POWER = '2', CMD_ENUM_DODGE = '3', CMD_ENUM_THUMP = '4', CMD_ENUM_MAX, } CMD_ENUM;
typedef struct instance_t { char name[16]; int role; int dodge; int hp; int mp; struct instance_t *peer; } INSTANCE_T;
void dsp_usage() { LOGD("\n\n选项:\n"); LOGD("\t1.攻击:使用攻击需消耗1MP 伤害1HP\n"); LOGD("\t2.蓄力:使用蓄力可增加1MP 伤害0HP\n"); LOGD("\t3.闪避:使用躲闪需消耗0MP 伤害0HP 躲避攻击\n"); LOGD("\t4.重击:使用重击需消耗2MP 伤害2HP 防御无效\n"); } int main(void) { char str_opt = 0; int opt = 0; int ret = 0; void (*do_callback)(INSTANCE_T *pinst);
INSTANCE_T inst1 = {{0}, 0}; INSTANCE_T inst2 = {{0}, 0}; strcpy(inst1.name, "勇士"); inst1.hp = 10; inst1.mp = 0; inst1.peer = &inst2; inst1.role = ROLE_YOU; strcpy(inst2.name, "恶龙"); inst2.hp = 20; inst2.mp = 3; inst2.peer = &inst1; inst2.role = ROLE_DRAGON; srandom((unsigned int)time(NULL)); dsp_usage(); while ( (str_opt = getchar()) != EOF ) { switch ( str_opt ) { case CMD_ENUM_ATTACK: do_attack(&inst1); break; case CMD_ENUM_POWER: do_power(&inst1); break; case CMD_ENUM_DODGE: do_dodge(&inst1); break; case CMD_ENUM_THUMP: do_thump(&inst1); break; case 'q': LOGD("Game over\n"); exit(0); default: continue; } switch ( (random() & 0x3) + '1' ) { case CMD_ENUM_ATTACK: do_attack(&inst2); break; case CMD_ENUM_POWER: do_power(&inst2); break; case CMD_ENUM_DODGE: do_dodge(&inst2); break; case CMD_ENUM_THUMP: do_thump(&inst2); break; default: break; } dsp_title(&inst1, &inst2); dsp_usage(); } LOGD("Game over\n"); exit(0); }
四种攻击模式的实现:
void do_attack(INSTANCE_T *pinst) { LOGX("%s准备攻击,", pinst->name); if ( 0 == pinst->mp ) { LOGX("MP不足!\n"); return; } pinst->mp--; if ( 0 == pinst->peer->dodge ) { pinst->peer->hp--; LOGX("发动攻击!造成掉血1点!\n"); } else { LOGX("我勒个去!攻击被%s闪避了!\n", pinst->peer->name); } pinst->peer->dodge = 0; } void do_power(INSTANCE_T *pinst) { LOGX("%s准备蓄力,", pinst->name); pinst->mp++; LOGX("MP:%d\n", pinst->mp); } void do_dodge(INSTANCE_T *pinst) { LOGX("%s准备闪避,", pinst->name); pinst->dodge = 0; LOGX("下回合生效!\n"); } void do_thump(INSTANCE_T *pinst) { LOGX("%s准备大招,", pinst->name); if ( pinst->role == ROLE_YOU ) { if ( pinst->mp < 2 ) { LOGX("MP不足!\n"); } else { if ( 0 == pinst->peer->dodge ) { pinst->peer->hp -= 2; LOGX("Avada Kedavra!!!!\n"); } else { LOGX("我勒个去!大招你也躲避了!\n"); } pinst->mp = 0; } } else { if ( pinst->mp < 3 ) { LOGX("巨龙在发呆...\n"); } else { LOGX("发动火焰吐吸!无法闪避!\n"); pinst->mp = 0; pinst->peer->hp -= 4; } } pinst->peer->dodge = 0; }
最后,再做一个屏幕输出的显示。
void dsp_title(INSTANCE_T *pinst1, INSTANCE_T *pinst2) { int ix = 0; printf("\033[2J"); LOGGREEN("+----------------------------------------+"); LOGGREEN("+----------------------------------------+\n"); LOGGREEN("| YOU HP: %2d: ", pinst1->hp); for ( ix = 1; ix <= HP_MAX; ix++ ) { if ( ix <= pinst1->hp ) { LOGGREEN("="); } else { LOGGREEN(" "); } } LOGGREEN(" |"); LOGGREEN("| DRANGON HP: %2d: ", pinst2->hp); for ( ix = 1; ix <= HP_MAX; ix++ ) { if ( ix <= pinst2->hp ) { LOGGREEN("="); } else { LOGGREEN(" "); } } LOGGREEN(" |\n"); LOGGREEN("| MP: %2d: ", pinst1->mp); for ( ix = 1; ix <= MP_MAX; ix++ ) { if ( ix <= pinst1->mp ) { LOGGREEN("="); } else { LOGGREEN(" "); } } LOGGREEN(" |"); LOGGREEN("| MP: %2d: ", pinst2->mp); for ( ix = 1; ix <= MP_MAX; ix++ ) { if ( ix <= pinst2->mp ) { LOGGREEN("="); } else { LOGGREEN(" "); } } LOGGREEN(" |\n"); LOGGREEN("+----------------------------------------+"); LOGGREEN("+----------------------------------------+\n"); LOGYELLOW("%s", msg); offset = 0; if ( pinst1->hp <= 0 ) { exit(0); LOGD("噢,你挂了!\n"); } else if ( pinst2->hp <= 0 ) { exit(0); LOGD("恭喜勇士,你获得了胜利\n"); } }
四、总结
巨龙AI明显不太够,玩家太强了哈哈!好吧,这是个有趣的自娱自乐游戏!
大家新村快乐、鸡年吉祥!
大家新村快乐、鸡年吉祥!