c语言大作业_2018 C语言大作业--21_Ekko制作教程

524f4eb0713492943ea16d44cb2f85db.png

同学们实现的效果:

de1cbcb552e120afe9965623e140caff.png
https://www.zhihu.com/video/1066249425780809728

以下是开发同学的相关文档:

《Ekko》设计报告

本组设计并编写的游戏《Ekko》,是一款引用了当下红火的网络游戏《英雄联盟》中的游戏角色Ekko为主角,由本组三名成员使用C语言编写的一款横屏动作闯关游戏。

一 设计思路

在选取游戏题材作为最终的课程设计目标时,一如许多组的同学一样,我们曾考虑过将一个现成的游戏拿来改编,但最后我们决定自己做一款游戏。而我们要做的第一步,则是明确我们要做一款什么样的游戏。受一款动作游戏《Super Hot》灵感,本组成员想要做一款主角拥有控制时间能力的动作游戏。

在《Super Hot》中,玩家操控的角色拥有一种令人着迷的能力:放慢时间,让原本正常的世界的时间流动速度变慢,从而拥有更强、更从容的反应能力来应对敌人。我们认为这是一个非常酷炫的游戏概念,并想要做一款能体现这一游戏概念的游戏。

受限于我们的知识储备,我们只能使用C语言来编写游戏,而与此同时,我们也只能用EasyX来进行绘图。因此,我们最终决定设计一款2D的动作游戏,而这款游戏能展现出令人着迷的控制时间的能力。

而在设计我们的主角的时候,我们亦曾想过做一个“能控制时间的忍者”,而之后我们注意到了在现今的网络游戏中大红大紫的竞技游戏《英雄联盟》之中,就有一个类似的能控制时间的角色:艾克(Ekko)。艾克是一名生长于名为祖安的城市的少年,拥有控制时间的能力,并利用这个能力惩奸除恶,践行自己的价值观,守护着祖安城。艾克的人设展现出令人钦佩的人性光彩,和他桀骜不羁的个性。我们几乎一拍即合,决定采用Ekko作为我们游戏的主角。

而在游戏构架的构思中,我们为了最大程度体现“控制时间”这一能力,决定设计一种关卡难度极大的游戏——需要玩家细腻的操作,并且正确地使用“时间暂停”这一能力。

谈及动作游戏的难度,最容易想到的有两点:1、地图的复杂性;2、敌人攻击的危险性。因此,在最初的构思中,我们决定给予主角仅仅一条生命——如同《超级马里奥》一般,被敌人的攻击命中,便会死亡。同时,我们会设计复杂而多变的地形,以及大量的敌人、更大量的弹幕。

而我们不能只关注游戏难度是否够高,而应同时关注玩家的游戏体验。所以我们必须将主角的操作细节设计得足够细腻——以回应玩家细腻的操作。

综上,我们的游戏的基本雏形便构建完毕——在祖安城内,一位名为Ekko的少年,在大量的敌人面前把玩着自己的控制时间的能力,灵巧地躲避敌人的各种攻击并前进,这就是我们想做出来的一款原创跑酷游戏。

二 功能描述

在我们组的《Ekko》的设计中,由我来担任Ekko的运动的编写,以及Ekko与地图中各种各样的互动。

以下为艾克——这名酷炫的时间刺客,需要具有什么样的基础功能,以及什么样的“画龙点睛”,才能给玩家一个不错的游戏体验。

1:显示素材。不可否认的是,对于计科专业的同学来说,期末课设最为直接的素材收集方式为搜索互联网。但是这对于我们组而言不可行——因为我们要做的游戏中,需要的元素大部分在网上找不到,原因则为我们游戏虽题材非原创,但游戏方式与界面却与原素材的相去甚远(比如英雄联盟中的3D建模下的艾克是无法应用在我们的游戏中的)。因此,我们组只能自己去绘制我们的素材。

此外,绘制好的素材需要放在特定文件夹内,以便编程时用代码读取这些素材;此外,我们组还需要学会如何利用EasyX,在游戏中显示透明的图层。

2:人物移动。在课程中,我们学习了最基本的人物移动方法:利用getchar函数和几个简单的判断,来实现人物坐标的改变。但这对于我们的Ekko是不够的——这个函数的读取模式存在着“第一次和第二次之间存在停顿”的问题。因此,我需要寻求更加优秀的算法来实现人物的移动。

3:与场景的碰撞。在许多简单的游戏中,与场景的碰撞可以简单的归结为“和一两个物体之间的碰撞判定”,但这个判定方式在一个更加复杂的地图中时不成立的——我们需要编写大量碰撞判断,这让代码变得冗杂,难以阅读和编写,容易出错,且不易调试。因此,我需要写一套“碰撞法则”,以方便后期的地图编写。如此,只需要一套法则,就可以应对各种各样的地图而不易出现问题。

4:时间暂停。这个功能是我们的游戏中的亮点。Ekko正是因为能够控制自己的时间,才能成为“撕裂时空的少年”。这一功能的实现方法很多。

5:正确的死亡。我需要编写艾克在合何时会死亡的代码。

三 分步骤实现方法

第一阶段:绘制素材,准备好人物图片与对应的遮罩图;

第二阶段:架构基本游戏框架,采用不同的源文件以封装不同的功能。利用掩码图将人物放入,调试直至能够正常的演示图片,并加入最简单的人物移动功能。为了使游戏运行更加顺畅,我花费了大量的时间来构建人物的移动,代码量多达一千行左右。以下为代码的一部分:

if ((GetAsyncKeyState(0x41) & 0x8000)) // a

{

if (Ekko_Speed_x >= -2.5)

{

Acceleration_x = -0.1;//获得加速度

Ekko_Speed_x += Acceleration_x;

}

else if (Ekko_Speed_x <= -3)

{

Acceleration_x = 0.8;

Ekko_Speed_x += Acceleration_x;

}

if (Crash_Wall())//如果要撞墙

{

Acceleration_x = 0;

Ekko_Speed_x = 0;

goto loop1;

}

if (Ekko_Face == 1)//变换方向

{

Ekko_Face = -1;

}

Ekko_x += Ekko_Speed_x;

if (DropOrNot == 0)

{

Status_check_i = 1;

}

else if (DropOrNot == 1)//检测空中是否按过AD

{

AD_in_Air = 1;

}

}

需要注意的是,单独的这一段代码并不能看出什么直接意义。这些变量的功能穿插于许许多多的函数中,牵一发而动全身。许多变量不仅用来记录数据,还用来记录状态。

第三阶段:优化人物移动,加入人物和环境的碰撞的法则并测试。这一阶段的完成,意味着地图编写工作可以正式开始;然而该阶段为开发过程最为艰难的部分之一。没有现成的物理引擎的支持,自己从头开始写,并非一件容易的事情,需要大量的耐心、细心,以及长时间的测试,同时这个阶段面临的BUG是最多的。

以下为碰撞代码的核心内容:

int ABS(float A, float B) //float型绝对值。单独定义并且用在下面的函数中

{

float C;

C = A - B;

if (C >= 0)

{

return C;

}

else

{

C = (-1)*C;

return C;

}

}

int Crash_Wall()//判断是否即将和地形碰撞。即将 碰撞 返还 1 ,否则返还 0

{

for (int i = 0; i < Block_Number; i++)

{

if (Ekko_Speed_x > 0)

{

if (

Ekko_x + Ekko_Width / 2 <= Land_Left[i] && Ekko_x + Ekko_Speed_x + Ekko_Width / 2 > Land_Left[i]

&&

Ekko_y + Ekko_High / 2 > Land_Top[i] && Ekko_y - Ekko_High / 2 < Land_Bottom[i]

)

{

LockedOne_x = i;

return 1;

//break;

}

else if (i == LockedOne_x && ABS(Land_Left[i], Ekko_x + Ekko_Width / 2) < 4)

{

return 1;

}

else

continue;

}

else if (Ekko_Speed_x < 0)

{

if (

Ekko_x - Ekko_Width / 2 >= Land_Right[i] && Ekko_x + Ekko_Speed_x - Ekko_Width / 2 < Land_Right[i]

&&

Ekko_y + Ekko_High / 2 > Land_Top[i] && Ekko_y - Ekko_High / 2 < Land_Bottom[i]

)

{

LockedOne_x = i;

return 1;

//break;

}

else if (i == LockedOne_x && ABS(Ekko_x - Ekko_Width / 2, Land_Right[i]) < 3)

{

return 1;

}

else

continue;

}

}

return 0;

}

int Crash_Ground()//判断和地面是否碰撞,即将碰撞返还1,否则返还0 加入了踩到地刺的判定

{

for (int i = 0; i < Block_Number; i++)

{

if (Ekko_Speed_y > 0)

{

if (

Ekko_y + Ekko_High / 2 <= Land_Top[i] && Ekko_y + Ekko_Speed_y + 0.06 + Ekko_High / 2 > Land_Top[i] //0.06是Y轴方向加速度

&&

Ekko_x + Ekko_Width / 2 > Land_Left[i] && Ekko_x - Ekko_Width / 2 < Land_Right[i]

)

{

LockedOne_y = i;

if (LockedOne_y == 6||LockedOne_y == 7 || LockedOne_y == 8 || LockedOne_y == 11 || LockedOne_y == 12 || LockedOne_y == 44 || LockedOne_y == 45 || LockedOne_y == 46 || LockedOne_y == 64 || LockedOne_y == 65 || LockedOne_y == 66)

DeadOrNot = 1;

return 1;

//break;

}

else

continue;

}

else if (DropOrNot == 1 && Ekko_Speed_y == 0)//悬空时速度为0

{

return 0;

}

else if (DropOrNot == 0 && Ekko_Speed_y == 0 && LockedOne_y == i && (Ekko_x + Ekko_Width / 2 < Land_Left[i] || Ekko_x - Ekko_Width / 2 > Land_Right[i]))//落地后速度为0但是踩空

{

return 1;

}

else if (DropOrNot == 0 && Ekko_Speed_y == 0 && LockedOne_y == i && (Ekko_x - Ekko_Width / 2 < Land_Right[i] && Ekko_x + Ekko_Width / 2 > Land_Left[i]))//落地后速度为0,踩实

{

return 0;

}

else if (Ekko_Speed_y < 0)

{

return 0;

}

}

return 0;

}

int Crash_Top()

{

for (int i = 0; i < Block_Number; i++)

{

if (Ekko_Speed_y < 0)

{

if (

Ekko_y - Ekko_High / 2 >= Land_Bottom[i] && Ekko_y + Ekko_Speed_y - Ekko_High / 2 < Land_Bottom[i]

&&

Ekko_x + Ekko_Width / 2 > Land_Left[i] && Ekko_x - Ekko_Width / 2 < Land_Right[i]

)

{

LockedOne_y = i;

return 1;

//break;

}

}

else

break;

}

return 0;

}

简而言之,这些代码实现了主角和任意设置好的矩形都能发生正确的碰撞,使得地图的开发变得简单——只需要记录各个地图板块的坐标即可。

第四阶段:测试人物和地图的碰撞,并加入冲刺能力、时间减缓能力,并测试。

冲刺代码:

static float SIN, COS;//记录角度

AD_in_Air=0;

MOUSEMSG mouse;

mouse.uMsg = false;

if (MouseHit())

{

mouse = GetMouseMsg();

}

if (mouse.uMsg== WM_RBUTTONDOWN && Dash_Check == 0&&Dash_limit==0) //准备冲刺

{

Dash_Speed = 11;

COS = ((mouse.x - Screen_Center_x) / sqrt((mouse.y - Screen_Center_y)*(mouse.y - Screen_Center_y) + (mouse.x - Screen_Center_x)*(mouse.x - Screen_Center_x)));

SIN= ((mouse.y - Screen_Center_y) / sqrt((mouse.y - Screen_Center_y)*(mouse.y - Screen_Center_y) + (mouse.x - Screen_Center_x)*(mouse.x - Screen_Center_x)));

Ekko_Speed_x = Dash_Speed * COS;//鼠标位置决定冲刺方向

Ekko_Speed_y = Dash_Speed * SIN;

Dash_Check = 1;

Dash_limit = 1;

if (!Crash_Wall()&&!Crash_Top()&&!Crash_Ground())

{

Ekko_x += Ekko_Speed_x;

Ekko_y += Ekko_Speed_y;

}

else

{

Ekko_Speed_x = 0;

Ekko_Speed_y = 0;

Dash_Check = 0;

Dash_limit = 0;

}

if (Dash_Check==1)

{

Status_check_i = 3;//图形演示变为冲刺

if (Ekko_Speed_x > 0)

Ekko_Face = 1;

else

Ekko_Face = -1;

DropOrNot = 1;

w_check = 1;

JumpOrNot = 1;

jump_limit_check = 1;

}

}

else if (Dash_Check == 1) //冲刺过程不可控

{

if (Dash_Speed > 3)

{

Dash_Speed -= 0.2;

}

Ekko_Speed_x = Dash_Speed * COS;

Ekko_Speed_y = Dash_Speed * SIN;

if (Crash_Wall())

{

Ekko_Speed_x = 0;

Dash_Check = 0;

}

if (Crash_Top())

{

Ekko_Speed_y = 0;

Dash_Check = 0;

}

if (Crash_Ground())

{

Ekko_Speed_y = 0;

Dash_Check = 0;

Dash_limit = 0;

}

if(Dash_Speed<=5)

{

Dash_Check = 0;

}

Ekko_x += Ekko_Speed_x;

Ekko_y += Ekko_Speed_y;

}

else //非冲刺的情况

... ...(其他功能)

第五阶段:加入人物的死亡功能——被敌人的子弹击中时死亡,坠入地底时也会死亡,碰到地刺的时候亦会死亡。

第六阶段:优化、加入与Ekko语音的音乐素材。

四 体会与总结

在最后完成游戏的一瞬间,心中固然有着千般喜悦,但苦涩感依然无法散去。这一个月的开发过程并不总是一帆风顺,在面对众多的BUG和技术难关时,自己知识的匮乏彻彻底底地暴露出来了,这也迫使自己进一步去学习新的知识。

令我高兴的是,游戏的效果不错——拥有着相当流畅的游戏体验、自己制作的素材活灵活现地展现在游戏中、游戏本身有着诸多趣味等等,依然会让我会心一笑。在这样的过程中,我领悟到了编程带来的无穷乐趣,以及编程的深奥。这样宝贵的经历,必将促使我进行更加深入的学习,以做出让自己更为满意的作品!

分步骤代码、素材、开发难点讲解视频、报告文档,可以从百度网盘下载:

https://pan.baidu.com/s/15lDd1bAwBjsZm6oUi5NHhA​pan.baidu.com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/346472.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Nutshell中的Java 8语言功能-第1部分

你好朋友&#xff0c; Java 8发布已经很长时间了&#xff0c;现在越来越多地被使用。 在本文中&#xff0c;我们将讨论以下Java 8主题。 1.功能接口 2&#xff0c;Lambda表达式 3.默认方法 1.功能界面 什么是功能接口&#xff1f; 与一种并且只有一种抽象方法的接口是功能…

做ppt用的小插图_如何用PPT做随机抽奖?

每到年底&#xff0c;每个公司都开始筹备年会活动。年会在员工们最期待的就是抽奖环节了。除了用专门的抽奖软件之外&#xff0c;PPT也可以做随机抽奖。今天就来解锁这个动画的做法。1&#xff0c;先设置好图片和文本&#xff1b;2&#xff0c;选中每一张幻灯片&#xff0c;选择…

mysql 隔离级别 快照_MySql的四种事务隔离级别

一、事务的四大特性(ACID)了解事务隔离级别之前不得不了解的事务的四大特性。1、原子性(Atomicity)事务开始后所有操作&#xff0c;要么全部做完&#xff0c;要么全部不做。事务是一个不可分割的整体。事务在执行过程中出错&#xff0c;会回滚到事务开始之前的状态&#xff0c;…

jsp mysql论坛_使用SSM和ajax做一个简易的论坛-01(简介和建表)

三月底刚学完SSM试着做了个简单的论坛&#xff0c;想分享一下&#xff0c;顺便整理一下自己的收获。一、demo介绍一个具有登录、注册功能&#xff0c;发帖、回帖功能的简易论坛。没有后台系统。设计逻辑类似于贴吧&#xff0c;发帖时自动附带一个一楼。二、使用的框架/库前端&a…

elastic 修改map_Amazon Elastic Map Reduce使用Apache Mahout计算建议

elastic 修改mapApache Mahout是一个“可扩展的机器学习库”&#xff0c;其中包括各种单节点和分布式推荐算法的实现。 在上一篇博客文章中&#xff0c; 我描述了如何在单个节点上实现在线推荐系统来处理数据。 如果数据太大而无法放入内存&#xff08;> 100M首选项数据点&a…

mysql 更新时间加数字_Mysql实战45讲笔记:8、聚合函数count

count(*)的实现方式在不同的MySQL引擎中&#xff0c;count()有不同的实现方式 1. MyISAM引擎把一个表的总行数存在了磁盘上&#xff0c;因此执行count()的时候会直接返回这个数&#xff0c;效率很高&#xff1b; 2. 而InnoDB引擎就麻烦了&#xff0c;它执行count(*)的时候&…

python学生管理系统类图_类图 python

广告关闭 腾讯云11.11云上盛惠 &#xff0c;精选热门产品助力上云&#xff0c;云服务器首年88元起&#xff0c;买的越多返的越多&#xff0c;最高返5000元&#xff01; 我正在研究一个庞大的遗留python类&#xff0c;它有很多方法。 我最终将复杂的方法分解成更小的部分&#x…

简单的测试可以防止最严重的故障

错误处理是软件开发中最困难且被忽略的部分之一&#xff0c;如果系统是分布式的&#xff0c;那么这将变得更加困难。 好的论文写在“ 简单测试可以预防最关键的故障” 主题上。 每个开发人员都应该阅读本文。 我将尝试总结本文的主要内容&#xff0c;但建议阅读该论文以获取有…

sql 两个 in_SQL基础知识——IN运算符

IN的作用IN运算符允许您在WHERE子句中指定多个值。IN运算符是多个OR条件的简写。IN的语法SELECT column_name(s) FROM table_name WHERE column_name IN (value1, value2, ...);或者SELECT column_name(s) FROM table_name WHERE column_name IN (SELECT STATEMENT);示例数据库…

pythonlist循环添加元素_python中 for循环之后 添加元素到列表失败?

import re ls list() dc dict() # 介词、连词、人称代词等自己统计 adverb [i, you, he, she, it, in, on, with, by, for, at, about, under, of, to, and, or, therefore, so, of, a] with open("老人与海.txt", moder, encodingutf-8) as f: lryh f.read() # …

开始协议处理句柄_基于smb协议的wmiexec浅析

前言之前研究过Crackmapexec这款工具&#xff0c;对这个工具基于smb协议的wmiexec执行方法产生的流量进行了分析&#xff0c;网上似乎还没有相关的文章&#xff0c;这里旨在抛砖引玉&#xff0c;简单梳理下整个过程&#xff0c;以初学者的视角&#xff0c;探索流量当中存在的奥…

apache camel_轻量级的开源集成:Apache Camel还是Spring集成?

apache camel首先&#xff0c;为全面披露信息&#xff0c;在过去的1.5年中&#xff0c; 我一直担任 FuseSource&#xff08;现为Red Hat&#xff09; 的顾问&#xff0c;为零售&#xff0c;运输&#xff0c;银行/金融等不同行业的大型和小型公司提供SOA和集成项目支持。我的专长…

科尔达服务101

我今天想写一篇简短的要点文章。 我真的很好奇我能多快出版此书。 所以走吧 这篇文章是关于Corda Services&#xff08;使用Corda 3.2版&#xff09;的。 这些是什么&#xff1f; 作为经常使用Spring的开发人员&#xff0c;我个人会说它们就像Beans。 Spring Beans可以做的还很…

intent隐式和显式_Neo4j:使隐式关系成为显式和双向关系

intent隐式和显式我最近阅读了Michal Bachman关于 Neo4j中双向关系的文章 &#xff0c;他建议对于某些关系类型&#xff0c;我们对关系的方向不那么感兴趣&#xff0c;因此可以在查询时忽略它。 他使用以下示例显示Neo Technology和GraphAware之间的合作关系&#xff1a; 两家…

mysql读写分离 存储过程_基于maxscale的读写分离部署笔记

使用maxscale搭建的读写分离架构&#xff0c;后期还可以再结合MHA做master的故障转移&#xff0c;这样业务层面上不需要做任何的改动即可。基于connect方式的不要使用。从库延迟他还会继续分发请求过去&#xff0c;暂时不适合生产使用。实验演示&#xff1a;目前的主从结构&…

python读书笔记2000_流畅的Python读书笔记

特殊方法的存在是为了Python解释器调用的&#xff0c;你自己并不需要去调用他们&#xff0c;比如说my_object.len()这种写法是没有的&#xff0c;应该使用len(my_object)。在使用len(my_object)的时候&#xff0c;如果my_object是一个自定义类的对象&#xff0c;那么Python会自…

antd 3升级命令_是时候拥有一个你自己的命令行工具了

本篇博客主要介绍了如何使用commander, inquirer以及chalk从零开始&#xff0c;创建属于自己的命令行工具。0. 一分钟体验首先我们先花一分钟的时间&#xff0c;体验一下创建自己的命令行cli工具是什么感觉。0.1. 新建项目目录假如我们的项目名称叫hello-cli&#xff0c;使用如…

找不到要去的声明_老汉将行李袋交由他人看管 去了一趟卫生间找不到人了.........

春节走亲访友难免多喝两杯&#xff0c;但酒后乘车却容易造成财物遗失。目前正值春运返程高峰&#xff0c;从沧州女儿家返程回山东老家的蔡先生就因为中午多喝了几杯酒&#xff0c;便将装有12000元生活费的行李袋弄丢了。好在沧州火车站派出所民警最终将蔡先生的失物找回&#x…

java可视化压缩_web可视化技术发展(1/6)

EverCraft一直在关注Web可视化技术的发展&#xff0c;在本系列文章里&#xff0c;小编将对国外一篇感觉很不错的综述性文章进行翻译&#xff0c;供这一领域的爱好者相互学习。这篇paper的信息为&#xff1a;“Mwalongo, F., et al., State-of-the-Art Report in Web-based Visu…

屏幕坏点检测图片_电视屏幕出现坏点?行家会这样做!

液晶电视经常会有几个亮点或暗点&#xff0c;这些通常被称为电视坏点。作为强迫症患者&#xff0c;面对这些屏幕坏点我们应该怎么做&#xff1f;下面跟小智聊聊这个问题吧&#xff01;首先&#xff0c;坏点形成的原因首先是因为液晶屏幕由很多点组成&#xff0c;每个点由RGB三原…