2d游戏人物动作实现(C语言)

news2025/1/15 19:51:06

没有接触制作小游戏前,感觉做游戏很不可思议,游戏里的人物是怎么移动的,怎么攻击,释放技能。。。。。。现在逐渐了解到之后,发现2d游戏人物的动作更多是图片的拼接,动作是否精细,由这个动作的帧数决定。这篇博客会简单实现2d人物的动作,效果如下。

2d人物动作展示

想实现这个效果其实很简单,思路如下:
1.创建图形库程序

#include<graphics.h>
	initgraph(int宽, int高);
	closegraph();//关闭窗口


2.导入图片素材

将装图片素材的文件导入到程序的同一文件夹下,需要素材的小伙伴可以私信我

 这是导入图片的步骤

给图片起一个名字
	IMAGE 图片名字;
加载图片
	loadimage(&图片名字,"图片路径",显示的宽,显示的高);
显示图片
	putimage(int x,int y,int w,int h,&图片名字,int xx,int yy);
	xx,yy表示在图片中取区域的起始位置
	w,h表示取的图片区域的大小
	x,y表示在图形界面显示的坐标

这里拿导入背景举例

#include<stdio.h>
#include<conio.h>//防止闪屏
#include<graphics.h>
int main()
{

	initgraph(1000, 650);
	IMAGE background;
	loadimage(&background, "Background\\background.bmp");
	putimage(0, 0, &background);
	_getch();
	closegraph();
	return 0;

}

 导入人物需要用到透明贴图技术(原理大家可以自行搜索,这里就不写了)

        背景图:黑色实物


        掩码图:白底黑洞


    具体过程
        先贴掩码图 AND方式 SRCAND

        putimage(int x,int y,&图片名,SRCAND);


        再贴背景图 PAINT方式 SRCPAINT

      putimage(int x,int y,&图片名,SRCAND);

因为我们的图片是长条形的,我们只需要取一部分,这里取宽400px,高300px的第一部分

 在上面背景图的代码中加入人物站立的代码,其中role.position控制人物的朝向

#include<stdio.h>
#include<conio.h>//防止闪屏
#include<graphics.h>
IMAGE background;
IMAGE standImg[2];//这里是2的原因是,我们人物需要左右各有一个站立的动作 背景图:0表示左边 1表示右边
IMAGE standImgY[2];//掩码图
struct actor {
	int x;
	int y;
	int position;//人物朝向
};
struct actor role = { 0,250,1 };

void loadResource()
{

	loadimage(&standImg[0], "Stand\\left.bmp");
	loadimage(&standImg[1], "Stand\\right.bmp");
	loadimage(&standImgY[0], "Stand\\lefty.bmp");
	loadimage(&standImgY[1], "Stand\\righty.bmp");
}

void drawRoleStand()
{
	putimage(0, 0, &background);
	putimage(role.x, role.y, 400, 300, &standImgY[role.position], 0, 0, SRCAND);
	putimage(role.x, role.y, 400, 300, &standImg[role.position], 0, 0, SRCPAINT);
}
int main()
{

	initgraph(1000, 650);

	loadimage(&background, "Background\\background.bmp");
	putimage(0, 0, &background);
	loadResource();
	drawRoleStand();
	_getch();
	closegraph();
	return 0;

}

 

3.给图片做位移:左右移动,挥砍,跳跃这些动作其实都是图片变换,这里拿左右移动举例

加上这部分代码实现人物左右移动,其余动作都是同理,关键部分已经在代码中注释

IMAGE moveImg[2];
IMAGE moveImgY[2];

void loadResource()//加载左右移动图片
{

	loadimage(&moveImg[0], "Move\\left.bmp");
	loadimage(&moveImg[1], "Move\\right.bmp");
	loadimage(&moveImgY[0], "Move\\lefty.bmp");
	loadimage(&moveImgY[1], "Move\\righty.bmp");
}


void moveRole()//当role.position=0时,每次向左移动5像素 向右同理
{
	switch (role.position)
	{
	case 0:
			role.x -= 5;
		break;
	case 1:
		role.x += 5;

		break;

	}
}

void drawRoleMove(int zhenshu)//根据position的值向左或者向右移动 因为我们的图片有8帧,每次选图片中400*(i-1)px开始的位置
{
	for (int i = 0; i < zhenshu; i++)
	{
		BeginBatchDraw();//双缓冲绘图防止闪屏
		putimage(0, 0,  &background);
		putimage(role.x, role.y, 400, 300, &moveImgY[role.position], 400 * i, 0, SRCAND);
		putimage(role.x, role.y, 400, 300, &moveImg[role.position], 400 * i, 0, SRCPAINT);
		moveRole();
		Sleep(20);//设置延迟
		EndBatchDraw();//双缓冲绘图
	}
}



void keyDown()//这里输入键盘按键和程序交互
{
	char userKey = _getch();  //C语言的原本的函数是getch() VS对它做了优化
	switch (userKey)
	{

	case'A':
	case'a':
	case 75:
		role.position = 0;
		drawRoleMove(8);//drawRoleMove(8)里面8的原因是,我们move的图片素材有8帧
		printf("左");//为了程序思路更清楚,可以不要
		break;
	case'd':
	case'D':
	case 77:
		role.position = 1;
		drawRoleMove(8);
		printf("右");
		break;
	}
}
int main()
{

	initgraph(1000, 650);

	loadimage(&background, "Background\\background.bmp");
	putimage(0, 0, &background);
	loadResource();
	while (true)
	{
		drawRoleStand();
		keyDown();
	}
	_getch();
	closegraph();
	return 0;

}

 

 加上上面代码,人物实现左右移动

剩余的跳跃,攻击......代码与移动基本无差(所以素材很重要,有素材基本就是换皮哈哈)

看到这的小伙伴记得点赞,收藏哦

下面附上完整代码,需要素材的小伙伴可以评论或者私信联系我

#include<stdio.h>
#include<conio.h>//防止闪屏
#include<graphics.h>
#include<easyx.h>
//数据设计-->基础知识+资源+游戏分析(角色的要素)
//透明贴图
IMAGE background;
IMAGE standImg[2];//背景图:0表示左边 1表示右边
IMAGE standImgY[2];
IMAGE moveImg[2];
IMAGE moveImgY[2];
IMAGE jumpImg[2];
IMAGE jumpImgY[2];
IMAGE jumpCut[2];
IMAGE jumpCutY[2];
IMAGE cutImg[2];
IMAGE cutImgY[2];
//角色属性
struct actor {
	int x;
	int y;
	int position;//人物朝向
};
//背景属性
struct bground

{
	int x;
	int y;
};
struct bground bgInfo = { 0,0 };
struct actor role = { 0,250,1 };
//初始化变量
void loadResource()
{
	//加载资源
	loadimage(&background, "Background\\background.bmp");//loadimage(&图片名字, "图片路径",1000,650); 加载图片
	loadimage(&standImg[0], "Stand\\left.bmp");
	loadimage(&standImg[1], "Stand\\right.bmp");
	loadimage(&standImgY[0], "Stand\\lefty.bmp");
	loadimage(&standImgY[1], "Stand\\righty.bmp");

	loadimage(&moveImg[0], "Move\\left.bmp");
	loadimage(&moveImg[1], "Move\\right.bmp");
	loadimage(&moveImgY[0], "Move\\lefty.bmp");
	loadimage(&moveImgY[1], "Move\\righty.bmp");

	loadimage(&jumpImg[0], "Jump\\left.bmp");
	loadimage(&jumpImg[1], "Jump\\right.bmp");
	loadimage(&jumpImgY[0], "Jump\\lefty.bmp");
	loadimage(&jumpImgY[1], "Jump\\righty.bmp");

	loadimage(&jumpCut[0], "JumpCut\\left.bmp");
	loadimage(&jumpCut[1], "JumpCut\\right.bmp");
	loadimage(&jumpCutY[0], "JumpCut\\lefty.bmp");
	loadimage(&jumpCutY[1], "JumpCut\\righty.bmp");

	loadimage(&cutImg[0], "Cut\\left.bmp");
	loadimage(&cutImg[1], "Cut\\right.bmp");
	loadimage(&cutImgY[0], "Cut\\lefty.bmp");
	loadimage(&cutImgY[1], "Cut\\righty.bmp");
}
//布局
void drawRoleStand()
{
	putimage(0, 0,1000,650, &background,bgInfo.x,bgInfo.y);
	putimage(role.x, role.y, 400, 300, &standImgY[role.position], 0,0,SRCAND);
	putimage(role.x, role.y, 400, 300, &standImg[role.position],0,0, SRCPAINT);
}
//逻辑-->用户逻辑

//根据人物方向做位移变化
void moveRole()
{
	switch (role.position)
	{
	case 0:
		if (role.x > -160)
		{
			role.x -= 5;
		}
		else
		{
			role.x = -160;
		}
		if (bgInfo.x > 0)
		{
			bgInfo.x -= 10;
		}
		else
		{
			bgInfo.x = 0;
		}
		break;
	case 1:
			role.x += 5;

			bgInfo.x += 10;

		break;

	}
}
//描述人物动作
void drawRoleMove(int zhenshu)
{
	for (int i = 0; i < zhenshu; i++)
	{
		BeginBatchDraw();
		putimage(0, 0, 1000, 650, &background, bgInfo.x, bgInfo.y);
		putimage(role.x, role.y, 400, 300, &moveImgY[role.position], 400*i, 0, SRCAND);
		putimage(role.x, role.y, 400, 300, &moveImg[role.position], 400*i, 0, SRCPAINT);
		moveRole();
		Sleep(20);
		EndBatchDraw();
	}
}
//跳跃
void drawRoleJump(int zhenshu)
{
	for (int i = 0; i < zhenshu; i++)
	{
		BeginBatchDraw();
		putimage(0, 0, 1000, 650, &background, bgInfo.x, bgInfo.y);
		putimage(role.x, role.y, 400, 300, &jumpImgY[role.position], 400 * i, 0, SRCAND);
		putimage(role.x, role.y, 400, 300, &jumpImg[role.position], 400 * i, 0, SRCPAINT);
		moveRole(); //跳跃时不做横向位移就不写这行
		Sleep(20);
		EndBatchDraw();
	}
}
void drawRoleCut(int franmeNum)
{
	for (int i = 0; i < franmeNum; i++)
	{
		BeginBatchDraw();
		putimage(0, 0, 1000, 650, &background, bgInfo.x, bgInfo.y);
		putimage(role.x, role.y, 400, 300, &cutImgY[role.position], 400 * i, 0, SRCAND);
		putimage(role.x, role.y, 400, 300, &cutImg[role.position], 400 * i, 0, SRCPAINT);
		moveRole();  //跳跃不做位移变化
		Sleep(50);
		EndBatchDraw();
	}
}
void drawRoleJumpCut(int frameNum)
{
	for (int i = 0; i < frameNum; i++)
	{
		BeginBatchDraw();
		putimage(0, 0, 1000, 650, &background, bgInfo.x, bgInfo.y);
		putimage(role.x, role.y, 400, 300, &jumpCutY[role.position], 400 * i, 0, SRCAND);
		putimage(role.x, role.y, 400, 300, &jumpCut[role.position], 400 * i, 0, SRCPAINT);
		moveRole();  //跳跃不做位移变化
		Sleep(50);
		EndBatchDraw();
	}
}
//操作游戏-->按键操作
//鼠标操作
void keyDown()
{
	char userKey = _getch();  //C语言的原本的函数是getch() VS对它做了优化
	switch (userKey)
	{

	case'A':
	case'a':
	case 75:
		role.position = 0;
		drawRoleMove(8);
		printf("左");
		break;
	case'd':
	case'D':
	case 77:
		role.position = 1;
		drawRoleMove(8);
		printf("右");
		break;
	case'j':
	case'J':
		drawRoleJumpCut(6);
		printf("跳砍");
		break;
	case'k':
		drawRoleCut(7);
		printf("跳砍");
		break;
	case' ':
		drawRoleJump(8);
		printf("跳");
		break;
	}
}
int main()
{
	loadResource();
	initgraph(1000, 650);
	while (true)
	{
		drawRoleStand();
		keyDown();
	}
	closegraph();
	return 0;
	
}

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

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

相关文章

第四十二章 Unity 下拉框 (Dropdown) UI

本章节我们介绍下拉框 (Dropdown)&#xff0c;我们点击菜单栏“GameObject”->“UI”->“Dropdown”&#xff0c;然后调整它的位置&#xff0c;效果如下 其实它的本质就是一个下拉列表&#xff0c;然后选择列表中的一个选项而已。大家在很多网页中应该可以看到类似的UI元…

asp.net+sqlserver学生学籍管理系统

1.系统登录模块&#xff1a;为了保证系统的安全性和保密性&#xff0c;便于用户的管理&#xff0c;对用户设置权限。 界面上需要输入用户名、密码、验证码以及用户类型。 用户类型&#xff1a;普通用户和管理员用户。 2.用户信息管理模块&…

Solr(4):Solr索引库说明及创建

1 索引库概述 索引库类似于mysql的数据库&#xff0c;所以如果要使用Solr必须创建一个索引库才能使用 2 使用solr管理页面去创建【不推荐】 2.1 打开solr的管理页面 2.2 点击add Core name&#xff1a;自定义名字 建议和instanceDir目录保持一样instanceDir&#xff1a;实例名…

两大巨头强强联手,为亿万旅行者提供完美旅程

‍数据智能产业创新服务媒体 ——聚焦数智 改变商业 这个“五一”你买到票了么&#xff1f; 今年五一火爆程度可谓“盛况空前”&#xff0c;4月28号&#xff08;放假前一天&#xff09;上海单日通往全国所有车站的车票售罄&#xff0c;这是115年以来首次出现这种情况。不仅是上…

javaScript---设计模式-提高复用性

目录 1、提高复用性的设计模式 2、基本结构与应用示例 2.1 享元模式 2.2 桥接模式 2.3 模板方法模式 2.4 JS的组合与继承 提高复用性的目的&#xff1a;①遵循DRY&#xff08;Dont Repeat Yourself&#xff09;原则&#xff1b;②减少代码量&#xff0c;节省开销 什么是好的复用…

Android安装apk出现 “安装包无效”或“安装包不兼容”的解决方案

Android 安装apk出现“安装包无效”或“安装包不兼容”解决方案 1. 问题出现2. 配置 build.gradle3. 生成Signed APK 1. 问题出现 使用Android Studio安装apk到手机一切正常&#xff0c;但是分享出去出现安装apk出现“安装包无效”或“安装包不兼容”问题 这种情况需要我们设…

MySQL之从一条记录说起 【InnoDB 记录结构下篇】

前言 本文章收录在MySQL性能优化原理实战专栏&#xff0c;点击此处查看更多优质内容。 本文摘录自 ▪ 小孩子4919《MySQL是怎样运行的&#xff1a;从根儿上理解MySQL》 上一篇文章讲了InnoDB有Compact、Redundant、Dynamic、Compressed4种⾏格式&#xff0c;其中主要讲了Com…

Java——按之字形顺序打印二叉树

题目链接 牛客在线oj题——按之字形顺序打印二叉树 题目描述 给定一个二叉树&#xff0c;返回该二叉树的之字形层序遍历&#xff0c;&#xff08;第一层从左向右&#xff0c;下一层从右向左&#xff0c;一直这样交替&#xff09; 数据范围&#xff1a;0≤n≤1500, 树上每个…

深入浅出字符编码

本文对应视频链接&#xff1a; 深入浅出字符编码 什么是编码格式 从一个小问题引入 我们在学习C语言的时候&#xff0c;有一道必做的题目是将大写字母转换成小写&#xff0c;相信有点基础的同学都能不加思索的写出下面的代码&#xff1a; char toLower(char upper){if (up…

大数据Doris(十四):数据模型的选择建议和列定义建议

文章目录 数据模型的选择建议和列定义建议 一、数据模型的选择建议 1、Aggregate数据模型选择<

如何快速给出解释——正交矩阵子矩阵的特征值的模必然不大于1

Memory 首先快速回忆一下正交矩阵的定义&#xff1a; A为n阶实矩阵&#xff0c;且满足A‘AE或是说AA’E&#xff0c;那么A为正交矩阵。 &#xff08;啊&#xff0c;多么简洁的定义&#xff09; 其次快速想到它的性质&#xff1a; ① 实特征值必然 或 其他复数…

qt几种常见安装包制作工具-Qt Installer Framework

Qt Installer Framework&#xff08;简称&#xff1a;QtIFW&#xff09;概述 QtIFW提供了一组工具和实用程序&#xff0c;可以一次性创建安装程序&#xff0c;并在所有支持的桌面Qt平台上部署它们&#xff0c;而无需重写源代码。安装程序将在运行它们的平台上具有本机外观和感…

第四节 特殊权限SUID、SGID、SBIT

1.Set UID 简称 SUID 简称 SUID 限制与功能&#xff1a; SUID权限仅对二进制程序有效&#xff1b; 执行者对于该程序需要具有x的执行权限&#xff1b; 本权限仅在执行该程序的过程中有效&#xff1b;  执行者将具有该程序拥有者的权限 特殊权限SUID、SGID、SBIT 例&am…

【分布族谱】Zipf分布及其Python可视化

文章目录 zipf分布简介zipfian和zipf对象zipf分布到zeta分布的变化情况分布族谱图 zipf分布简介 #mermaid-svg-mG901pJXpTYFT7Bk {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-mG901pJXpTYFT7Bk .error-icon{fill:…

Spring Boot 如果防护 XSS + SQL 注入攻击

Spring Boot 如果防护 XSS SQL 注入攻击 XSS跨站脚本攻击XSS漏洞介绍XSS漏洞分类防护建议 SQL注入攻击SQL注入漏洞介绍防护建议mybatis是如何做到sql预编译的呢 SpringBoot中如何防止XSS攻击和sql注入创建Xss请求过滤类XssHttpServletRequestWraper把请求过滤类XssHttpServlet…

使用fork函数创建一个进程

pid_t fork(void) fork函数调用成功&#xff0c;返回两次 &#xff08;1&#xff09;返回值为0&#xff0c;代表当前进程是子进程 &#xff08;2&#xff09;返回值为非负数&#xff0c;代表当前进程是父进程 &#xff08;3&#xff09;调用失败&#xff0c;则返回-1 代码如…

【人工智能概论】 K折交叉验证

【人工智能概论】 K折交叉验证 文章目录 【人工智能概论】 K折交叉验证一. 简单验证及其缺点1.1 简单验证简介1.2 简单验证的缺点 二. K折交叉验证2.1 K折交叉验证的思路2.2 小细节2.3 K折交叉验证的缺点2.4 K折交叉验证的代码 一. 简单验证及其缺点 1.1 简单验证简介 简单验…

join 语句使用

目录 前言 创建数据 知识点补充 Join算法Index Nested-Loop 小结&#xff1a; Join算法Block Nested-Loop join_buffer放不下驱动表情况 小结&#xff1a; 小表是什么&#xff1f; 总结&#xff1a; 参考内容 前言 在实际开发中&#xff0c;我们一般会有两类问题&a…

腾讯云2核4G服务器5M带宽轻量CPU性能、流量和系统盘测试

腾讯云轻量应用服务器2核4G5M配置&#xff0c;自带5M公网带宽&#xff0c;5M带宽下载速度峰值可达640KB/秒&#xff0c;系统盘为60GB SSD盘&#xff0c;每月500GB流量包&#xff0c;折合每天16GB流量。腾讯云百科来详细说下腾讯云轻量应用服务器2核4G5M配置、CPU型号处理器主频…

威联通nas服务器中勒索病毒被encrypted勒索病毒攻击怎么办有哪些预防措施

威联通是一家专业提供网络存储设备和应用方案的公司&#xff0c;旗下NAS服务器因为实用、多功能而深受用户喜欢&#xff0c;但是NAS服务器在使用过程中也面临许多安全问题&#xff0c;例如被encrypted勒索病毒攻击。下面将为大家介绍encrypted勒索病毒在威联通NAS服务器上的危害…