- 分享
我完成(一半)力!
- @ 2026-1-10 19:46:46
开始前,请确保你已经按照教程做了.
思路
其实也没别的,只是感觉有一个比较好用的思路推荐一下
EMMM
反正就是看到了一种随机算法,叫 柏林噪声 ,能生成比较自然的纹理,但我不用纹理,就稍微改了一下,让他能生成比较自然的地形:
int bj[120];
void dj__(){
int bj_[126];
for(int i=0;i<126;i++){
bj_[i]=rand_(750,769);
}
for(int i=0;i<120;i++){
bj[i]=0;
for(int j=i;j<6+i;j++) bj[i]+=bj_[j];
bj[i]/=6;
}
}
代码(知道你们只看这里)
bits.h:
//这将是一个easyx的神人头文件
/*
1.函数
1.qian() 把画布挪至最前方(最好必用)
2.in() 输入
3._out() 在画布上新建一行文字
4.outph() 显示图片
5.getph() 把图片名加上地址
例(显示一张图片):
string s="start.jpg";(一定要一个变量)
s=getph(s);(加上地址,默认是.exe地址+\ph\(就是把照片存到.exe所在文件夹下再建一个ph文件夹,在里面存照片))
outph(0,0,s);(在0,0显示图片)
2.头文件
包含所有头文件,最好不要改
*/
#include <windows.h>
#include <easyx.h>
#include <conio.h>
#include <string>
#include <vector>
#include <map>
#include <bits/stdc++.h>
using namespace std;
int rand_(int l,int r);
struct body{
int x,y;
int to_x,to_y;
int xf,yf;
}b[3];
// 全局变量,记录每个按键的上一次状态
map<char, bool> keyPrevState;
void qian_() {
HWND hWnd = GetHWnd();
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}
void chbkc(COLORREF W){
setbkcolor(W);
cleardevice();
}//清空画布
void drso(int xx,int xy,int chx,int chy,COLORREF W){
int yx=xx+chx,yy=xy+chy;
setfillcolor(W);
solidrectangle(xx,xy,yx,yy);
}//绘制填充矩形
////
int bj[120];
void dj__(){
int bj_[126];
for(int i=0;i<126;i++){
bj_[i]=rand_(750,769);
}
for(int i=0;i<120;i++){
bj[i]=0;
for(int j=i;j<6+i;j++) bj[i]+=bj_[j];
bj[i]/=6;
}
}
int dt[1200];
void rdt(){
for(int i=0;i<120;i++){
for(int j=10*i;j<10*(i+1);j++) dt[j]=bj[i];
}
}
int dux[1000][120];
int dxbj=0;
void dx(bool x){
if(x==0){
if(dxbj==0) dxbj=999;
else dxbj=dxbj-1;
}
if(x==1){
if(dxbj==999) dxbj=0;
else dxbj++;
}
if(dux[dxbj][0]==0){
dj__();
for(int i=0;i<120;i++) dux[dxbj][i]=bj[i];
}
else{
for(int i=0;i<120;i++) bj[i]=dux[dxbj][i];
}
rdt();
}
////只有dx能用,给的参数是向左还是向右,0为左,dt[i]表示x=i时地的高度
bool in(char x, bool flag = 1) {
char e = x;
if (flag) {
e -= 32; // 转换为大写(假设x是小写)
}
return (GetAsyncKeyState(x) || GetAsyncKeyState(e));
}
void _out(string s, int x, int y,COLORREF c=WHITE) {
setbkmode(TRANSPARENT);
settextcolor(c);
settextstyle(20, 0, _T("宋体"));
TCHAR tstr[256];
_stprintf(tstr, _T("%s"), s.c_str());
outtextxy(x, y, tstr);
}
// 显示图片函数
// 参数: x - x坐标, y - y坐标, filename - 图片文件名
// 返回值: bool - 成功返回true,失败返回false
// 显示图片函数
void outph(int x, int y, const std::string& s) {
// 加载图片
IMAGE img;
loadimage(&img, s.c_str());
// 在指定位置显示图片
putimage(x, y, &img);
}
string getph(const string& pl) {
char buffer[MAX_PATH] = {0};
GetModuleFileNameA(NULL, buffer, MAX_PATH);
string path(buffer);
size_t pos = path.find_last_of("\\/");
if (pos != string::npos) {
path = path.substr(0, pos) + "\\ph\\" + pl;
} else {
path = path + "\\ph\\" + pl;
}
return path;
}
// 侧身人形改进版 - 更明显的侧身效果
void drawman(int x, int y,bool fla) {
int baseX = x - 10;
int baseY = y - 30;
// 1. 头 - 侧脸(椭圆)
setfillcolor(RGB(255, 205, 148));
solidrectangle(baseX + 10, baseY + 1, baseX + 15, baseY + 8);
solidrectangle(baseX + 12, baseY + 8, baseX + 13, baseY + 9);
setfillcolor(RGB(0, 0, 0));
solidrectangle(baseX + 10, baseY + 1, baseX + 15, baseY + 2);
if(fla==0) solidrectangle(baseX + 10, baseY + 4, baseX + 11, baseY + 5);
else solidrectangle(baseX + 14, baseY + 4, baseX + 15, baseY + 5);
if(fla==1) solidrectangle(baseX + 10, baseY + 3, baseX + 11, baseY + 4);
else solidrectangle(baseX + 14, baseY + 3, baseX + 15, baseY + 4);
setfillcolor(RGB(255, 205, 148)); // 肤色
if(fla==1) solidrectangle(baseX + 10, baseY + 10, baseX + 12, baseY + 20);
else solidrectangle(baseX + 14, baseY + 10, baseX + 16, baseY + 20);
// 2. 身体 - 侧身(窄矩形)
setfillcolor(RGB(220, 100, 100)); // 红色上衣
solidrectangle(baseX + 11, baseY + 10, baseX + 15, baseY + 22);
// 3. 腿 - 侧身(一条腿)
setfillcolor(RGB(50, 50, 50)); // 黑色裤子
solidrectangle(baseX + 12, baseY + 22, baseX + 14, baseY + 30);
// 4. 前臂 - 在身体前方
setfillcolor(RGB(255, 205, 148)); // 肤色
if(fla==0) solidrectangle(baseX + 10, baseY + 10, baseX + 12, baseY + 20);
else solidrectangle(baseX + 14, baseY + 10, baseX + 16, baseY + 20);
}
int rand_(int l, int r) {
static unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
static std::mt19937 gen(seed);
std::uniform_int_distribution<> dis(l, r);
return dis(gen);
}
bool u_d_(body xx,body yy){
if(xx.x==yy.x && xx.y==yy.y) return 1;
return 0;
}
int jumpv=-20;
bool isjump=0;
bool go(int zy,int& x,int& y){
if(zy==0){
if(x-6<0){
x-=6;
x+=1200;
if(isjump==0) y=dt[x];
return 1;
}
x-=6;
if(isjump==0) y=dt[x];
}
if(zy==1){
if(x+6>=1200){
x+=6;
x-=1200;
if(isjump==0) y=dt[x];
return 1;
}
x+=6;
if(isjump==0) y=dt[x];
}
return 0;
}
void jump(int& x,int& y){
if(y>=dt[x]){
isjump=0;
jumpv=-20;
y=dt[x];
return ;
}
y+=jumpv;
if(y>=dt[x]) y=dt[x];
jumpv=min(jumpv+1,20);
}
int n=3;
void start_csh(){
cont:;
for(int i=0;i<n;i++){
con:;
b[i].x=rand_(10,1190);
b[i].y=rand_(10,790);
b[i].to_x=rand_(10,1190);
b[i].to_y=rand_(10,790);
b[i].xf=b[i].to_x-b[i].x;
b[i].yf=b[i].to_y-b[i].y;
if(abs(b[i].xf)+abs(b[i].yf)>20) goto con;
}
if(u_d_(b[0],b[1]) || u_d_(b[0],b[2]) || u_d_(b[1],b[2])) goto cont;
}
main.cpp:
#include"bits.h"
using namespace std;
int main(){
std::srand(static_cast<unsigned int>(
std::chrono::system_clock::now().time_since_epoch().count()));
initgraph(1200,800);
qian_();
string lo=getph("ling.png");
outph(0,0,lo);
start_csh();
// for(int i=0;i<n;i++){
// cout << b[i].x<<' '<<b[i].y<<endl;
// cout << b[i].xf<<' '<<b[i].yf<<endl;
// }
dx(0);
bool manf=1;
int manx=350,many=0;
go(manf,manx,many);
while(1){
int uuu=1;
BeginBatchDraw();
if(in('a') || in(VK_LEFT,0)) manf=0;
else if(in('d') || in(VK_RIGHT,0)) manf=1;
else uuu=0;
if((in('w') || in(VK_UP,0)) && !isjump){
isjump=1;
many--;
}
chbkc(RGB(160, 82, 45));
for(int i=0;i<1200;i++) drso(i,0,1,dt[i],RGB(135, 206, 235));
_out(to_string(dxbj),0,0,BLACK);
bool wk=0;
if(uuu==1) wk=go(manf,manx,many);
if(wk){
if(manx<300) dx(1);
else dx(0);
}
if(isjump){
jump(manx,many);
}
drawman(manx,many,manf);
EndBatchDraw();
Sleep(15);
}
return 0;
}
备注
1.此代码含有约20%的AI成分,但注释是自己写的,而且核心和50%多的函数是自己写的(防止有人说不是我写的)
2.请确保你已经按照
照做,否则出错我不负任何责任
3.请确保你用C++14或以上版本,否则出错我不负任何责任
4.建议新建项目时创建一个文件夹
5.仅支持DEV
2 comments
-
Myobot @ 2026-1-24 9:16:40
同学你好,
首先,感谢你分享你的代码和思路。从你的代码中可以看出,你尝试实现了一个基于柏林噪声(Perlin Noise)的地形生成算法,并将其应用在一个简单的2D平台游戏中。这是一个非常有趣且具有挑战性的项目,涉及到随机算法、图形渲染和游戏逻辑等多个方面。
不过,我注意到你的回复中提到“教程被ban了”,这可能意味着你无法访问原帖中的教程链接,导致在环境配置或理解上遇到了一些困难。作为信息学竞赛的教练,我的职责是引导你自主解决问题,而不是直接提供可运行的代码。因此,我将从以下几个方面为你提供思路和指导:
1. 分析你的代码结构与核心逻辑
你的项目主要分为两部分:
bits.h:包含了图形渲染、地形生成、人物绘制和物理模拟(移动、跳跃)的核心函数。main.cpp:主循环,处理用户输入、更新游戏状态并渲染画面。
核心算法分析:
- 你提到的“柏林噪声”实际上是一维的平滑随机地形生成。你的
dj__()函数通过生成126个随机数,然后对每6个连续值取平均,得到120个地形高度值。这是一种滑动窗口平均滤波,可以有效平滑随机噪声,生成连续的地形。 dx()函数管理一个环形缓冲区 (dux),用于存储和读取不同位置的地形数据,实现了“无限”地形的效果。
2. 可能遇到的问题及调试思路
由于教程链接失效,你可能会在以下方面遇到问题:
a) 开发环境配置(EasyX图形库)
- 问题:你的代码严重依赖
EasyX图形库。如果未正确安装或配置,编译会失败。 - 解决思路:
- 确保你使用的是 Dev-C++ 并已安装 EasyX 库。你可以通过搜索引擎查找“Dev-C++ 安装 EasyX”的最新教程。
- 在 Dev-C++ 中,创建项目时,项目类型应选择“Windows Application”,而不是控制台程序。
- 检查
#include <easyx.h>是否能正确找到头文件。可能需要手动指定库路径。
b) 资源文件路径问题
- 你的代码通过
getph()函数构建图片路径,期望在可执行文件同目录下的ph文件夹中找到ling.png。 - 解决思路:
- 确保你的项目目录下确实存在
ph文件夹,并且其中包含ling.png文件。 - 如果图片加载失败,游戏启动时背景会显示异常。你可以在
outph调用后添加简单的错误检查(例如,检查图片尺寸是否为0),或者暂时注释掉背景图片的显示,用纯色背景代替,以隔离问题。
- 确保你的项目目录下确实存在
c) 地形生成算法的理解与改进
- 你的地形生成算法 (
dj__()和rdt()) 是一维的,且平滑窗口固定为6。这可能导致地形变化不够“自然”(柏林噪声通常是多维的,并利用梯度进行插值)。 - 引导思考:
- 你能解释一下
dux这个二维数组(dux[1000][120])的作用吗?它如何实现“无限”地形? - 当前算法的时间复杂度是多少?如果地形块更多(比如1200改为10000),性能会如何?
- 如何调整平滑窗口的大小(代码中的6)来改变地形的“粗糙度”?
- 你能解释一下
3. 算法优化与扩展建议
如果你想进一步优化或扩展此项目,可以考虑以下方向:
-
真正的柏林噪声:
- 研究经典的Perlin Noise算法。它通过定义网格点上的随机梯度向量,并在网格之间进行平滑插值(通常使用三次Hermite插值)来生成更自然的连续噪声。
- 你可以尝试实现一个简化版的二维Perlin Noise来生成地形高度图。
-
物理引擎的完善:
- 当前的跳跃物理 (
jump函数) 模拟了简单的重力加速度。考虑添加水平速度衰减(摩擦力)、更精确的碰撞检测(目前只是判断y >= dt[x])以及斜坡处理。 - 如何检测人物是否站在地面上(
isjump的逻辑)?目前的逻辑在快速移动时可能不准确。
- 当前的跳跃物理 (
-
代码结构与可读性:
- 将游戏状态(如人物位置、速度、地形数据)封装到一个
Game类中。 - 使用枚举类型代替魔术数字(如
manf=0表示向左)。 - 将地形生成、渲染、物理更新等逻辑分离到不同的函数或模块中。
- 将游戏状态(如人物位置、速度、地形数据)封装到一个
4. 调试技巧
如果程序运行出现崩溃、黑屏或逻辑错误,请尝试:
- 分模块测试:注释掉游戏主循环,先单独测试地形生成函数
dj__()和rdt(),输出一些高度值看看是否符合预期。 - 简化渲染:先不用图片背景和人物精灵,只用矩形和线条绘制地形和人物,确保核心逻辑正确。
- 输出调试信息:在控制台输出关键变量(如
manx,many,isjump,jumpv)的值,观察其变化是否符合物理规律。
总结
你的项目已经具备了地形生成、人物移动、基础物理和图形渲染的雏形,这是一个很好的起点。遇到教程链接失效的问题,正是锻炼你独立查找资料、阅读文档和调试代码能力的机会。
下一步行动建议:
- 首先确保 EasyX 开发环境配置正确。
- 然后,分步运行和测试你的代码,从最简单的显示一个窗口开始,逐步添加地形、人物、控制逻辑。
- 如果遇到具体的编译错误或运行时问题,可以再来讨论,我会引导你分析错误信息并找到解决方案。
请记住,在信息学竞赛和编程学习中,遇到问题并解决问题的过程本身就是最宝贵的经验。期待看到你完善后的作品!
-
@ 2026-1-24 9:15:53
主包,你的教程被ban了,T-T
- 1