通常我们认为,纯C(即不使用C艹)很难实现跨平台的游戏。这是由于它支持的图形库非常少,一般需要调用系统句柄才能进行图形化。但是很显然这是一个及其费时费力还容易出错的方式。所以,在这篇文章里,我希望给大家介绍一些比较轻松的制作C语言的跨平台游戏的方式。
引擎绝对是个好东西,它帮你简化了许多繁琐而重复的构建阶段的实现。所以我们通常希望有一个好用的引擎。这里有我能找到的所有跨平台C语言库。
不管你采用了哪个图形库,游戏逻辑都不会变化太多。以下是一个适用与所有游戏的游戏逻辑。
这套流程/逻辑可以用于几乎所有游戏。
其实很推荐使用流程图来理清思路。
特别要注意各种“边界”值。即你想要把数轴的原点归为哪边?这个问题可以用文氏图来解决。
虽说编程范式没有最好与最坏之分,但绝对有适合一定领域的编程范式。这里,我们通常建议使用函数式编程。
编程方式,即编程规范。有些人认为开发过程越快就越好,可事情远没有这么简单。比如你为了快速开发使用了a,b,c ...... x,y,z共26个变量,结果你有一段时间去做别的项目了,回来拾起旧项目时一脸蒙蔽:"这都啥玩意阿?"。所以,应该把代码写得易于阅读,层次分明,注释有用。(这里表扬Python)
这是一个“简单”的打飞机游戏,使用C语言和Ncurses库开发。不管你承认与否,这真的是一个开始游戏编程的极好的地方。
编译时记得链接上你的Ncurses库
/*
Finished Version 0.1
Complitet: cd Desktop && gcc -o test01.out Shooter01.c -lncurses && ./test01.out
*/
#include <ncurses.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/* Global */
int HEIGHT, WIDTH, MAP_Y, MAP_X, MAP_HEIGHT, MAP_WIDTH, Timer, Hp, Score, Energy;
struct Pos *Bullets;
struct Pos *Enemies;
int Bullets_len, Bullets_full;
int Enemies_len, Enemies_full;
/* == Structs == */
struct Pos
{
int x;
int y;
};
/* == Tools == */
/* == Starting & Ending == */
void starting(void)
{
initscr();
// 准备工作
noecho(); // 取消回显
raw(); // 取消缓冲区
nodelay(stdscr, 1); // 对于getch()不等待
keypad(stdscr, 1); // 可以读取特殊字符
curs_set(0); // 光标不可见
getmaxyx(stdscr, HEIGHT, WIDTH); // 获取屏幕长宽
// 初始化游戏
Timer = 0;
Hp = 3;
Score = 0;
Energy = 100;
MAP_HEIGHT = 30;
MAP_WIDTH = 42;
Bullets_len =30;
Bullets_full=0;
Bullets = (struct Pos *)malloc(Bullets_len * sizeof(struct Pos));
for(int bullet=0; bullet<Bullets_len; bullet++)
{
Bullets[bullet].x=-1;
Bullets[bullet].y=-1;
}
Enemies_len =30;
Enemies_full=0;
Enemies = (struct Pos *)malloc(Enemies_len * sizeof(struct Pos));
for(int enemy=0; enemy<Enemies_len; enemy++)
{
Enemies[enemy].x=-1;
Enemies[enemy].y=-1;
}
MAP_Y = 2;
MAP_X = (WIDTH-MAP_WIDTH)/2;
// 开始界面
char title[] = "= Shooter v0.1 =";
mvprintw(HEIGHT/2, (WIDTH-strlen(title))/2, "%s", title);
char message[] = "[Press any key to start]";
mvprintw(HEIGHT-3, (WIDTH-strlen(message))/2, "%s", message);
char tips[] = "Moving: W A (Energy-1) Shooting: J (Energy-5) Quit: Q Get Energy by killing enemies!";
mvprintw(HEIGHT-1, (WIDTH-strlen(tips))/2, "%s", tips);
refresh();
while(getch()==ERR)
{
usleep(1000);
}
clear(); //清屏
refresh();
}
void ending(void)
{
// 结束界面
char title[] = "= Game Over =";
mvprintw(HEIGHT/2, (WIDTH-strlen(title))/2, "%s", title);
char message[] = "[Press any key to quit]";
mvprintw(HEIGHT-2, (WIDTH-strlen(message))/2, "%s", message);
refresh();
while(getch()==ERR)
{
usleep(1000);
}
clear(); //清屏
refresh();
endwin();
exit(0);
}
/* Operation */
// 出界判定
int on_map(int x, int y)
{
if(x<0 || x>=MAP_WIDTH || y<0 || y>=MAP_HEIGHT)
{
return 0;
}
else return 1;
}
void new_bullet(struct Pos player)
{
// 加大内存
if(Bullets_len==Bullets_full)
{
Bullets = realloc(Bullets, Bullets_len + 30*sizeof(struct Pos));
for(int index=Bullets_len; index<Bullets_len+30; index++)
{
Bullets[index].x=-1;
Bullets[index].y=-1;
}
}
// 新建子弹
for(int index=0; index<Bullets_len; index++)
{
if(Bullets[index].x==-1) //x=-1就算空位
{
Bullets[index].x=player.x+1;
Bullets[index].y=player.y-1;
Bullets_full++;
break;
}
}
}
// 销毁子弹
void destroy_bullet(int bullet)
{
Bullets[bullet].x=-1;
Bullets[bullet].y=-1;
Bullets_full--;
}
// 移动子弹
void move_bullets(void)
{
for(int bullet=0; bullet<Bullets_len; bullet++)
{
if(on_map(Bullets[bullet].x, Bullets[bullet].y) && Bullets[bullet].x!=-1)
{
Bullets[bullet].y--;
}
else if(Bullets[bullet].x!=-1)
{
destroy_bullet(bullet);
continue;
}
}
}
void new_enemies(int sum)
{
// 加大内存
if(Enemies_len==Enemies_full)
{
Enemies = realloc(Enemies, Enemies_len + 30*sizeof(struct Pos));
for(int index=Enemies_len; index<Enemies_len+30; index++)
{
Enemies[index].x=-1;
Enemies[index].y=-1;
}
}
// 新建对手
for(int index=0; index<Enemies_len; index++)
{
if(Enemies[index].x==-1) //x=-1就算空位
{
srand(Timer);
Enemies[index].x=rand()%MAP_WIDTH;
Enemies[index].y=0;
Enemies_full++;
break;
}
}
}
// 销毁对手
void destroy_enemy(int enemy)
{
Enemies[enemy].x=-1;
Enemies[enemy].y=-1;
Enemies_full--;
Score += 1;
}
// 移动对手
void move_enemies(void)
{
for(int enemy=0; enemy<Enemies_len; enemy++)
{
if(on_map(Enemies[enemy].x, Enemies[enemy].y))
{
Enemies[enemy].y++;
}
else if(Enemies[enemy].x!=-1)
{
destroy_enemy(enemy);
}
}
}
// 撞击判定
void judge_hits(struct Pos player)
{
for(int enemy=0; enemy<Enemies_len; enemy++)
{
if(on_map(Enemies[enemy].x, Enemies[enemy].y))
{
for(int bullet=0; bullet<Bullets_len; bullet++)
{
if(on_map(Bullets[bullet].x, Bullets[bullet].y))
{
if(abs(Bullets[bullet].x-Enemies[enemy].x)<=1 && Bullets[bullet].y==Enemies[enemy].y) // 对手与子弹
{
destroy_bullet(bullet);
destroy_enemy(enemy);
Score+=99;
Energy+=10;
}
}
}
// 玩家与对手
if(abs(player.x+1-Enemies[enemy].x)<=1 && player.y==Enemies[enemy].y)
{
Hp-=1;
destroy_enemy(enemy);
Score-=99999;
Energy+=100;
}
}
}
}
/* == Drawing == */
// 画地图
void draw_map(void)
{
mvprintw(MAP_Y-1, MAP_X-1, "###########################################");
for(int index=MAP_Y-1; index<=MAP_Y+MAP_HEIGHT; index++)
{
mvprintw(index, MAP_X-1, "#");
mvprintw(index, MAP_X+MAP_WIDTH, "#");
}
mvprintw(MAP_Y+MAP_HEIGHT, MAP_X-1, "###########################################");
}
// 画玩家
void draw_player(struct Pos pos, struct Pos last_pos)
{
char player[]="/|\\";
mvprintw(MAP_Y+pos.y, MAP_X+pos.x, "%s", player);
}
// 画子弹
void draw_bullets(void)
{
for(int bullet=0; bullet<Bullets_len; bullet++)
{
if(on_map(0, Bullets[bullet].y))
{
mvprintw(MAP_Y+Bullets[bullet].y, MAP_X+Bullets[bullet].x, "^");
}
}
}
// 画对手
void draw_enemies(void)
{
for(int enemy=0; enemy<Enemies_len; enemy++)
{
if(on_map(0, Enemies[enemy].y))
{
mvprintw(MAP_Y+Enemies[enemy].y, MAP_X+Enemies[enemy].x, "V");
}
}
}
int main(void)
{
starting();
char input;
struct Pos player_pos, player_last_pos;
player_pos.x = MAP_WIDTH/2-1;
player_last_pos.x = player_pos.x;
player_pos.y = MAP_HEIGHT-2;
player_last_pos.y = player_pos.y;
Bullets_full=0;
// 游戏主循环
while(1)
{
// Inputs
input = getch();
if(input=='q')
{
break;
}
if(input=='a' && on_map(player_pos.x-2, 0) && Energy>=1)
{
player_last_pos.x = player_pos.x;
player_pos.x-=2;
Energy--;
}
if(input=='d' && on_map(player_pos.x+2+3, 0) && Energy>=1)
{
player_last_pos.x = player_pos.x;
player_pos.x+=2;
Energy--;
}
if(input=='j' && Energy>=5)
{
new_bullet(player_pos);
Energy-=5;
}
// Draw
clear();
draw_map();
mvprintw(MAP_Y+MAP_HEIGHT+2, MAP_X-1, "Hp: %d", Hp);
mvprintw(MAP_Y+MAP_HEIGHT+2, MAP_X+MAP_WIDTH-20, "Score: %d", Score);
mvprintw(MAP_Y+MAP_HEIGHT+3, MAP_X-1, "Energy: %d", Energy);
draw_player(player_pos, player_last_pos);
draw_bullets();
draw_enemies();
// Update
move_bullets();
if(Timer%20==0) new_enemies(1);
if(Timer%10==0) move_enemies();
judge_hits(player_pos);
if(Hp<1) ending();
// Tests
mvprintw(1, MAP_X+MAP_WIDTH+2, "Screen WIDTH, HEIGHT: %d, %d", WIDTH, HEIGHT);
mvprintw(2, MAP_X+MAP_WIDTH+2, "MAP X,Y: %d, %d", MAP_X, MAP_Y);
mvprintw(3, MAP_X+MAP_WIDTH+2, "MAP WIDTH, HEIGHT: %d, %d", MAP_WIDTH, MAP_HEIGHT);
mvprintw(4, MAP_X+MAP_WIDTH+2, "Bullets Len, Full: %d, %d", Bullets_len, Bullets_full);
mvprintw(5, MAP_X+MAP_WIDTH+2, "Enemies Len, Full: %d, %d", Enemies_len, Enemies_full);
mvprintw(7, MAP_X+MAP_WIDTH+2, "Player Pos: %d, %d", player_pos.x, player_pos.y);
mvprintw(8, MAP_X+MAP_WIDTH+2, "Timer: %d", Timer);
mvprintw(1, 1, "Bullets:");
for(int index=0; index<Bullets_len; index++)
{
mvprintw(2+index/3, 2+15*(index%3), "%d: %d, %d", index, Bullets[index].x, Bullets[index].y);
}
mvprintw(Bullets_len/3+3, 1, "Enemies:");
for(int index=0; index<Enemies_len; index++)
{
mvprintw(Bullets_len/3+4+index/3, 2+15*(index%3), "%d: %d, %d", index, Enemies[index].x, Enemies[index].y);
}
// Time
refresh();
Timer++;
usleep(15000);
}
ending();
return 0;
}
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm
我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI
几个月前,我读了一篇关于rubygem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:
这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub
我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain
无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD
在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList()Obt
?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------