摘要
本文详细分析了一个使用C++编写的简易2D控制台动作游戏。该游戏实现了角色移动、攻击、技能释放等核心游戏机制,通过ASCII字符构建游戏场景,展现了基础游戏开发的核心技术要点。文章将从游戏架构、核心功能、代码实现、优化方向等方面进行全面剖析,为初学者提供游戏开发的实践参考。
1. 游戏概述
本游戏是一个基于Windows控制台的回合制战斗游戏,采用俯视视角的2D平面设计。玩家控制角色"p"在13×25大小的封闭场景中与敌人"@"战斗,通过WASD移动,空格键发射炮弹,Enter键释放震爆弹技能。
游戏采用关卡递增设计,每关BOSS血量会提升10%,具有简单的成长系统。主要游戏元素包括:
玩家角色(p)
敌人(@)
炮弹(*)
场景边界(=)
空白区域(空格)
2. 核心系统分析
2.1 输入处理系统
游戏使用Windows API的GetAsyncKeyState
函数实现实时按键检测:
cpp
#define KEY_DOWN(vKey) ((GetAsyncKeyState(vKey) & 0x8000) ? 1:0)
这种处理方式相比标准C++的输入方法有以下优势:
无需等待回车即可响应
支持多键同时检测
响应速度更快
键位映射:
W(87)/A(65)/S(83)/D(68):移动控制
空格(32):发射炮弹
Enter(13):释放技能
2.2 游戏物理系统
游戏实现了简单的碰撞检测和运动系统:
碰撞检测:通过坐标比对实现
cpp
if(xx==xxx &&yy==yyy) // 炮弹命中检测 if(xxx==x&&y==yyy) // 敌人接触伤害
运动系统:
玩家移动:即时响应按键
炮弹运动:沿发射方向直线移动
敌人AI:每3帧向玩家位置移动一步
2.3 状态管理系统
游戏通过变量管理各种状态:
hp1
/hp2
:玩家和敌人血量cd
:技能冷却计时器q
:眩晕效果计时器f
:记录玩家当前朝向
3. 代码结构解析
3.1 数据定义部分
cpp
char wutai[13][25] = {...}; // 场景地图数组 int x,y; // 玩家坐标 int xxx,yyy; // 敌人坐标 int hp1,hp2; // 双方血量
采用固定大小的二维数组存储场景,这种设计:
优点:实现简单,访问快速
缺点:场景大小固定,缺乏灵活性
3.2 主游戏循环
游戏采用经典的游戏循环结构:
输入处理
状态更新
渲染输出
延时控制
cpp
while(1) { // 1. 处理输入 if (KEY_DOWN(87))... // 2. 更新游戏状态 if(g==1)... // 3. 渲染 for(int i=0; i<13; i++)... // 4. 胜负判断 if(hp1<=0)... }
3.3 特殊效果实现
震爆弹技能:
cpp
if (KEY_DOWN(13)&&cd==0){ q=50; // 眩晕持续时间 cd=500; // 冷却时间 // 全屏闪光效果 for(int i=0; i<13; i++){ for(int j=0; j<25; j++) cout<<"█"; } }
这种实现虽然简单,但有效创造了视觉冲击效果。
重点
操作说明运行代码时会显示
代码:
#include<iostream>
#include<windows.h>
#define KEY_DOWN(vKey) ((GetAsyncKeyState(vKey) & 0x8000) ? 1:0)
#define KEY_UP(vKey) ((GetAsyncKeyState(vKey) & 0x8000) ? 0:1)
#include<bits/stdc++.h>
#include <windows.h>
#include <conio.h>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
int n,m,f=1,k=1;
char wutai[13][25] = {
{'=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','='},
{'=',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','='},
{'=',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','='},
{'=',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','='},
{'=',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','='},
{'=',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','='},
{'=',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','='},
{'=',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','='},
{'=',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','='},
{'=',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','='},
{'=',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','='},
{'=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','='}
};
int x=2,y=2,l=0,boos=100,cd=0;;
int ff,xx,yy,g=0,xxx=10,yyy=20,hp1=100,hp2=100;
int q=0;
void print(){
//*
cout<<"操作说明:"<<endl;
cout<<" 1.上:w 下:s 左:a 右:d"<<endl;
cout<<" 2.释放技能(震爆弹:震晕对手几秒):Entre"<<endl;
cout<<" 3.发射炮弹:空格 朝所在方向发射"<<endl;
system("pause") ;
system("cls");
//*/
}
int main() {
for(int i=0; i<=100; i++) {
cout<<endl<<endl;
cout<<"加载中";
for(int j=i%4; j>=0; j--) {
cout<<".";
}
cout<<endl;
cout<<endl<<endl<<endl<<endl;
for(int j=0; j<=i; j++) {
cout<<"▋";
}
cout<<endl;
cout<<" "<<i<<"%"<<endl;
system("cls");
}
system("pause") ;
system("cls");
print();
while(1) {
cout<<"第"<<k<<"关"<<endl;
k++;
hp2=boos;
boos=boos+boos/10;
hp1=100;
Sleep(500);
x=2;
y=2;
yyy=20;
xxx=10;
while(1) {
l++;
if (KEY_DOWN(87)&&x-1>=1) {//w
x-=1;
f=1;
}
if (KEY_DOWN(65)&&y-1>=1) {//a
y-=1;
f=3;
}
if (KEY_DOWN(83)&&x+1<11) {//s
x+=1;
f=4;
}
if (KEY_DOWN(68)&&y+1<22) {//d
f=2;
y+=1;
}
if (KEY_DOWN(32)&&g!=1) {//空格
g=1;
ff=f;
xx=x;
yy=y;
}
if (KEY_DOWN(13)&&cd==0) {//空格
q=50;
cd=500;
for(int i=0; i<13; i++) {
for(int j=0; j<25; j++) {
cout<<"█";
}
cout<<endl;
}
Sleep(500);
}
cout<<"x="<<x<<" y="<<y<<" f="<<f<<" HP="<<hp1<<" boos HP"<<hp2<<" CD:"<<cd<<endl;
for(int i=0; i<13; i++) {
for(int j=0; j<25; j++) {
if(i==x && j==y&&i==xxx&&j==yyy)cout<<"X";
else if(i==x && j==y) {
cout<<"p";
} else if(i==xx&&j==yy &&g==1) {
cout<<"*";
} else if(i==xxx&&j==yyy ) {
cout<<"@";
} else cout<<wutai[i][j];
}
cout<<endl;
}
if(g==1) {
if(ff==1&&xx-1>=1) {
xx-=1;
} else if(ff==2&&yy+1<22) {
yy+=1;
} else if(ff==3&&yy-1>=1) {
yy-=1;
} else if(ff==4&&xx+1<11) {
xx+=1;
} else {
g=0;
}
}
if(q==0) {
if(x<xxx&&l%3==0) {
xxx-=1;
} else if(y<yyy&&l%3==0) {
yyy-=1;
} else if(x>xxx&&l%3==0) {
xxx+=1;
} else if(y>yyy&&l%3==0) {
yyy+=1;
}
}
if(q>0){
q--;
}
if(cd>0){
cd--;
}
if(xx==xxx &&yy==yyy) {
hp2-=5;
g=0;
}
if(xxx==x&&y==yyy)hp1-=0.5;
if(hp1<=0) {
system("cls");
cout<<"you die"<<endl;
Sleep(500);
system("pause");
system("cls");
break;
} else if(hp2<=0) {
system("cls");
cout<<"you win"<<endl;
Sleep(500);
system("pause");
system("cls");
break;
}
system("cls");
}
}
return 0;
}
/*
=========================
= =
= =
= =
= =
= =
= =
= =
= =
= =
= =
= =
=========================
*/