【C语言】-------天天酷跑

1.代码介绍

        1.游戏背景的设计

        2.实现玩家奔跑

        3.实现玩家跳跃

        4.优化帧等待

        5.使用结构体封装障碍物

        6.封装后障碍物的初始化

        7.显示多个障碍物

        8.实现玩家下蹲技能

        9.添加柱子障碍物

        10.优化障碍物的出现频率

        11.实现碰撞检测

        12.添加音效,添加血条

        13.判断游戏结束,添加初始化界面

        14.解决死亡障碍

        15.通过障碍物后自动加分

        16.判断游戏胜利

相关素材可以上网查找,也可以私聊我!

2.运行结果展示

3.项目代码

        1.tools.h

#pragma once
#include <graphics.h>

//返回距离上一次调用间隔的时间(单位:ms),第一次调用时返回0
int getDelay(); 

void putimagePNG(int  picture_x, int picture_y, IMAGE* picture);

// 适用于 y <0 以及y>0的任何情况
void putimagePNG2(int x, int y, IMAGE* picture);
void putimagePNG2(int x, int y, int winWidth, IMAGE* picture);

// 判断两个矩形是否相交
bool rectIntersect(int a1X, int a1Y, int a2X, int a2Y,
    int b1X, int b1Y, int b2X, int b2Y);

void  preLoadSound(const char* name);
void  playSound(const char* name);

void drawBloodBar(int x, int y, int width, int height, int lineWidth, int boardColor, int emptyColor, int fillColor, float percent);

        2.easyx.h


#pragma once

#ifndef WINVER
#define WINVER 0x0400			// Specifies that the minimum required platform is Windows 95 and Windows NT 4.0.
#endif

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0500		// Specifies that the minimum required platform is Windows 2000
#endif

#ifndef _WIN32_WINDOWS
#define _WIN32_WINDOWS 0x0410	// Specifies that the minimum required platform is Windows 98
#endif

#ifdef UNICODE
	#pragma comment(lib,"EasyXw.lib")
#else
	#pragma comment(lib,"EasyXa.lib")
#endif


#ifndef __cplusplus
#error EasyX is only for C++
#endif

#include <windows.h>
#include <tchar.h>

// EasyX Window Properties
#define EX_SHOWCONSOLE		1		// Maintain the console window when creating a graphics window
#define EX_NOCLOSE			2		// Disable the close button
#define EX_NOMINIMIZE		4		// Disable the minimize button
#define EX_DBLCLKS			8		// Support double-click events


// Color constant
#define	BLACK			0
#define	BLUE			0xAA0000
#define	GREEN			0x00AA00
#define	CYAN			0xAAAA00
#define	RED				0x0000AA
#define	MAGENTA			0xAA00AA
#define	BROWN			0x0055AA
#define	LIGHTGRAY		0xAAAAAA
#define	DARKGRAY		0x555555
#define	LIGHTBLUE		0xFF5555
#define	LIGHTGREEN		0x55FF55
#define	LIGHTCYAN		0xFFFF55
#define	LIGHTRED		0x5555FF
#define	LIGHTMAGENTA	0xFF55FF
#define	YELLOW			0x55FFFF
#define	WHITE			0xFFFFFF

// Color conversion macro
#define BGR(color)	( (((color) & 0xFF) << 16) | ((color) & 0xFF00FF00) | (((color) & 0xFF0000) >> 16) )


class IMAGE;

// Line style class
class LINESTYLE
{
public:
	LINESTYLE();
	LINESTYLE(const LINESTYLE &style);
	LINESTYLE& operator = (const LINESTYLE &style);
	virtual ~LINESTYLE();

	DWORD	style;
	DWORD	thickness;
	DWORD	*puserstyle;
	DWORD	userstylecount;
};

// Fill style class
class FILLSTYLE
{
public:
	FILLSTYLE();
	FILLSTYLE(const FILLSTYLE &style);
	FILLSTYLE& operator = (const FILLSTYLE &style);
	virtual ~FILLSTYLE();

	int			style;				// Fill style
	long		hatch;				// Hatch pattern
	IMAGE*		ppattern;			// Fill image
};

// Image class
class IMAGE
{
public:
	int getwidth() const;			// Get the width of the image
	int getheight() const;			// Get the height of the image

private:
	int			width, height;		// Width and height of the image
	HBITMAP		m_hBmp;
	HDC			m_hMemDC;
	float		m_data[6];
	COLORREF	m_LineColor;		// Current line color
	COLORREF	m_FillColor;		// Current fill color
	COLORREF	m_TextColor;		// Current text color
	COLORREF	m_BkColor;			// Current background color
	DWORD*		m_pBuffer;			// Memory buffer of the image

	LINESTYLE	m_LineStyle;		// Current line style
	FILLSTYLE	m_FillStyle;		// Current fill style

	virtual void SetDefault();		// Set the graphics environment as default

public:
	IMAGE(int _width = 0, int _height = 0);
	IMAGE(const IMAGE &img);
	IMAGE& operator = (const IMAGE &img);
	virtual ~IMAGE();
	virtual void Resize(int _width, int _height);			// Resize image
};



// Graphics window related functions

HWND initgraph(int width, int height, int flag = 0);		// Create graphics window
void closegraph();											// Close graphics window


// Graphics environment related functions

void cleardevice();											// Clear device
void setcliprgn(HRGN hrgn);									// Set clip region
void clearcliprgn();										// Clear clip region

void getlinestyle(LINESTYLE* pstyle);						// Get line style
void setlinestyle(const LINESTYLE* pstyle);					// Set line style
void setlinestyle(int style, int thickness = 1, const DWORD *puserstyle = NULL, DWORD userstylecount = 0);	// Set line style
void getfillstyle(FILLSTYLE* pstyle);						// Get fill style
void setfillstyle(const FILLSTYLE* pstyle);					// Set fill style
void setfillstyle(int style, long hatch = NULL, IMAGE* ppattern = NULL);		// Set fill style
void setfillstyle(BYTE* ppattern8x8);						// Set fill style

void setorigin(int x, int y);								// Set coordinate origin
void getaspectratio(float *pxasp, float *pyasp);			// Get aspect ratio
void setaspectratio(float xasp, float yasp);				// Set aspect ratio

int  getrop2();						// Get binary raster operation mode
void setrop2(int mode);				// Set binary raster operation mode
int  getpolyfillmode();				// Get polygon fill mode
void setpolyfillmode(int mode);		// Set polygon fill mode

void graphdefaults();				// Reset the graphics environment as default

COLORREF getlinecolor();			// Get line color
void setlinecolor(COLORREF color);	// Set line color
COLORREF gettextcolor();			// Get text color
void settextcolor(COLORREF color);	// Set text color
COLORREF getfillcolor();			// Get fill color
void setfillcolor(COLORREF color);	// Set fill color
COLORREF getbkcolor();				// Get background color
void setbkcolor(COLORREF color);	// Set background color
int  getbkmode();					// Get background mode
void setbkmode(int mode);			// Set background mode

// Color model transformation related functions
COLORREF RGBtoGRAY(COLORREF rgb);
void RGBtoHSL(COLORREF rgb, float *H, float *S, float *L);
void RGBtoHSV(COLORREF rgb, float *H, float *S, float *V);
COLORREF HSLtoRGB(float H, float S, float L);
COLORREF HSVtoRGB(float H, float S, float V);


// Drawing related functions

COLORREF getpixel(int x, int y);				// Get pixel color
void putpixel(int x, int y, COLORREF color);	// Set pixel color

void line(int x1, int y1, int x2, int y2);		// Draw a line

void rectangle	   (int left, int top, int right, int bottom);	// Draw a rectangle without filling
void fillrectangle (int left, int top, int right, int bottom);	// Draw a filled rectangle with a border
void solidrectangle(int left, int top, int right, int bottom);	// Draw a filled rectangle without a border
void clearrectangle(int left, int top, int right, int bottom);	// Clear a rectangular region

void circle		(int x, int y, int radius);		// Draw a circle without filling
void fillcircle (int x, int y, int radius);		// Draw a filled circle with a border
void solidcircle(int x, int y, int radius);		// Draw a filled circle without a border
void clearcircle(int x, int y, int radius);		// Clear a circular region

void ellipse	 (int left, int top, int right, int bottom);	// Draw an ellipse without filling
void fillellipse (int left, int top, int right, int bottom);	// Draw a filled ellipse with a border
void solidellipse(int left, int top, int right, int bottom);	// Draw a filled ellipse without a border
void clearellipse(int left, int top, int right, int bottom);	// Clear an elliptical region

void roundrect	   (int left, int top, int right, int bottom, int ellipsewidth, int ellipseheight);		// Draw a rounded rectangle without filling
void fillroundrect (int left, int top, int right, int bottom, int ellipsewidth, int ellipseheight);		// Draw a filled rounded rectangle with a border
void solidroundrect(int left, int top, int right, int bottom, int ellipsewidth, int ellipseheight);		// Draw a filled rounded rectangle without a border
void clearroundrect(int left, int top, int right, int bottom, int ellipsewidth, int ellipseheight);		// Clear a rounded rectangular region

void arc	 (int left, int top, int right, int bottom, double stangle, double endangle);	// Draw an arc
void pie	 (int left, int top, int right, int bottom, double stangle, double endangle);	// Draw a sector without filling
void fillpie (int left, int top, int right, int bottom, double stangle, double endangle);	// Draw a filled sector with a border
void solidpie(int left, int top, int right, int bottom, double stangle, double endangle);	// Draw a filled sector without a border
void clearpie(int left, int top, int right, int bottom, double stangle, double endangle);	// Clear a rounded rectangular region

void polyline	 (const POINT *points, int num);								// Draw multiple consecutive lines
void polygon	 (const POINT *points, int num);								// Draw a polygon without filling
void fillpolygon (const POINT *points, int num);								// Draw a filled polygon with a border
void solidpolygon(const POINT *points, int num);								// Draw a filled polygon without a border
void clearpolygon(const POINT *points, int num);								// Clear a polygon region

void polybezier(const POINT *points, int num);									// Draw three square Bezier curves
void floodfill(int x, int y, COLORREF color, int filltype = FLOODFILLBORDER);	// Fill the area



// Text related functions
void outtextxy(int x, int y, LPCTSTR str);				// Output a string at the specified location
void outtextxy(int x, int y, TCHAR c);					// Output a char at the specified location
int textwidth(LPCTSTR str);								// Get the width of a string
int textwidth(TCHAR c);									// Get the width of a char
int textheight(LPCTSTR str);							// Get the height of a string
int textheight(TCHAR c);								// Get the height of a char
int drawtext(LPCTSTR str, RECT* pRect, UINT uFormat);	// Output a string in the specified format within the specified area.
int drawtext(TCHAR c, RECT* pRect, UINT uFormat);		// Output a char in the specified format within the specified area.

// Set current text style.
//		nHeight: The height of the text
//		nWidth: The average width of the character. If 0, the scale is adaptive.
//		lpszFace: The font name
//		nEscapement: The writing angle of the string, 0.1 degrees, defaults to 0.
//		nOrientation: The writing angle of each character, 0.1 degrees, defaults to 0.
//		nWeight: The stroke weight of the character
//		bItalic: Specify whether the font is italic
//		bUnderline: Specify whether the font is underlined
//		bStrikeOut: Specify whether the font has a strikeout
//		fbCharSet: Specifies the character set
//		fbOutPrecision: Specifies the output accuracy of the text
//		fbClipPrecision: Specifies the clip accuracy of the text
//		fbQuality: Specifies the output quality of the text
//		fbPitchAndFamily: Specifies a font family that describes a font in a general way
void settextstyle(int nHeight, int nWidth, LPCTSTR lpszFace);
void settextstyle(int nHeight, int nWidth, LPCTSTR lpszFace, int nEscapement, int nOrientation, int nWeight, bool bItalic, bool bUnderline, bool bStrikeOut);
void settextstyle(int nHeight, int nWidth, LPCTSTR lpszFace, int nEscapement, int nOrientation, int nWeight, bool bItalic, bool bUnderline, bool bStrikeOut, BYTE fbCharSet, BYTE fbOutPrecision, BYTE fbClipPrecision, BYTE fbQuality, BYTE fbPitchAndFamily);
void settextstyle(const LOGFONT *font);	// Set current text style
void gettextstyle(LOGFONT *font);		// Get current text style



// Image related functions
void loadimage(IMAGE *pDstImg, LPCTSTR pImgFile, int nWidth = 0, int nHeight = 0, bool bResize = false);					// Load image from a file (bmp/gif/jpg/png/tif/emf/wmf/ico)
void loadimage(IMAGE *pDstImg, LPCTSTR pResType, LPCTSTR pResName, int nWidth = 0, int nHeight = 0, bool bResize = false);	// Load image from resources (bmp/gif/jpg/png/tif/emf/wmf/ico)
void saveimage(LPCTSTR pImgFile, IMAGE* pImg = NULL);																		// Save image to a file (bmp/gif/jpg/png/tif)
void getimage(IMAGE *pDstImg, int srcX, int srcY, int srcWidth, int srcHeight);												// Get image from device
void putimage(int dstX, int dstY, const IMAGE *pSrcImg, DWORD dwRop = SRCCOPY);												// Put image to device
void putimage(int dstX, int dstY, int dstWidth, int dstHeight, const IMAGE *pSrcImg, int srcX, int srcY, DWORD dwRop = SRCCOPY);		// Put image to device
void rotateimage(IMAGE *dstimg, IMAGE *srcimg, double radian, COLORREF bkcolor = BLACK, bool autosize = false, bool highquality = true);// Rotate image
void Resize(IMAGE* pImg, int width, int height);	// Resize the device
DWORD* GetImageBuffer(IMAGE* pImg = NULL);			// Get the display buffer of the graphics device
IMAGE* GetWorkingImage();							// Get current graphics device
void SetWorkingImage(IMAGE* pImg = NULL);			// Set current graphics device
HDC GetImageHDC(IMAGE* pImg = NULL);				// Get the graphics device handle


// Other functions

int	getwidth();			// Get the width of current graphics device
int	getheight();		// Get the height of current graphics device

void BeginBatchDraw();	// Begin batch drawing mode
void FlushBatchDraw();	// Refreshes the undisplayed drawing
void FlushBatchDraw(int left, int top, int right, int bottom);	// Refreshes the undisplayed drawing
void EndBatchDraw();	// End batch drawing mode and refreshes the undisplayed drawing
void EndBatchDraw(int left, int top, int right, int bottom);	// End batch drawing mode and refreshes the undisplayed drawing

HWND GetHWnd();								// Get the handle of the graphics window
const TCHAR* GetEasyXVer();						// Get version of EasyX library

// Get user input as a dialog box
bool InputBox(LPTSTR pString, int nMaxCount, LPCTSTR pPrompt = NULL, LPCTSTR pTitle = NULL, LPCTSTR pDefault = NULL, int width = 0, int height = 0, bool bOnlyOK = true);



// Message
//
//	Category	Type				Description
//
//	EX_MOUSE	WM_MOUSEMOVE		Mouse moves
//				WM_MOUSEWHEEL		Mouse wheel is rotated
//				WM_LBUTTONDOWN		Left mouse button is pressed
//				WM_LBUTTONUP		Left mouse button is released
//				WM_LBUTTONDBLCLK	Left mouse button is double-clicked
//				WM_MBUTTONDOWN		Middle mouse button is pressed
//				WM_MBUTTONUP		Middle mouse button is released
//				WM_MBUTTONDBLCLK	Middle mouse button is double-clicked
//				WM_RBUTTONDOWN		Right mouse button is pressed
//				WM_RBUTTONUP		Right mouse button is released
//				WM_RBUTTONDBLCLK	Right mouse button is double-clicked
//
//	EX_KEY		WM_KEYDOWN			A key is pressed
//				WM_KEYUP			A key is released
//
//	EX_CHAR		WM_CHAR
//
//	EX_WINDOW	WM_ACTIVATE			The window is activated or deactivated
//				WM_MOVE				The window has been moved
//				WM_SIZE				The size of window has changed

// Message Category
#define EX_MOUSE	1
#define EX_KEY		2
#define EX_CHAR		4
#define EX_WINDOW	8

// Message Structure
struct ExMessage
{
	USHORT message;					// The message identifier
	union
	{
		// Data of the mouse message
		struct
		{
			bool ctrl		:1;		// Indicates whether the CTRL key is pressed
			bool shift		:1;		// Indicates whether the SHIFT key is pressed
			bool lbutton	:1;		// Indicates whether the left mouse button is pressed
			bool mbutton	:1;		// Indicates whether the middle mouse button is pressed
			bool rbutton	:1;		// Indicates whether the right mouse button is pressed
			short x;				// The x-coordinate of the cursor
			short y;				// The y-coordinate of the cursor
			short wheel;			// The distance the wheel is rotated, expressed in multiples or divisions of 120
		};

		// Data of the key message
		struct
		{
			BYTE vkcode;			// The virtual-key code of the key
			BYTE scancode;			// The scan code of the key. The value depends on the OEM
			bool extended	:1;		// Indicates whether the key is an extended key, such as a function key or a key on the numeric keypad. The value is true if the key is an extended key; otherwise, it is false.
			bool prevdown	:1;		// Indicates whether the key is previously up or down
		};

		// Data of the char message
		TCHAR ch;

		// Data of the window message
		struct
		{
			WPARAM wParam;
			LPARAM lParam;
		};
	};
};

// Message Function
ExMessage getmessage(BYTE filter = -1);										// Get a message until a message is available for retrieval
void getmessage(ExMessage *msg, BYTE filter = -1);							// Get a message until a message is available for retrieval
bool peekmessage(ExMessage *msg, BYTE filter = -1, bool removemsg = true);	// Get a message if any exist, otherwise return false
void flushmessage(BYTE filter = -1);										// Flush the message buffer

        3.tools.cpp

#include <stdio.h>
#include <Windows.h>
#include "tools.h"
#include<mmsystem.h>  //播放音乐
#pragma comment(lib,"winmm.lib")  //播放音乐

#include <mmsystem.h>
#pragma comment(lib, "winmm.lib")


int getDelay() {
    static unsigned long long lastTime = 0;
    unsigned long long currentTime = GetTickCount();
    if (lastTime == 0) {
        lastTime = currentTime;
        return 0;
    }
    else {
        int ret = currentTime - lastTime;
        lastTime = currentTime;
        return ret;
    }
}

// 载入PNG图并去透明部分
void putimagePNG(int  picture_x, int picture_y, IMAGE* picture) //x为载入图片的X坐标,y为Y坐标
{
    DWORD* dst = GetImageBuffer();    // GetImageBuffer()函数,用于获取绘图设备的显存指针,EASYX自带
    DWORD* draw = GetImageBuffer();
    DWORD* src = GetImageBuffer(picture); //获取picture的显存指针
    int picture_width = picture->getwidth(); //获取picture的宽度,EASYX自带
    int picture_height = picture->getheight(); //获取picture的高度,EASYX自带
    int graphWidth = getwidth();       //获取绘图区的宽度,EASYX自带
    int graphHeight = getheight();     //获取绘图区的高度,EASYX自带
    int dstX = 0;    //在显存里像素的角标

    // 实现透明贴图 公式: Cp=αp*FP+(1-αp)*BP , 贝叶斯定理来进行点颜色的概率计算
    for (int iy = 0; iy < picture_height; iy++)
    {
        for (int ix = 0; ix < picture_width; ix++)
        {
            int srcX = ix + iy * picture_width; //在显存里像素的角标
            int sa = ((src[srcX] & 0xff000000) >> 24); //0xAArrggbb;AA是透明度
            int sr = ((src[srcX] & 0xff0000) >> 16); //获取RGB里的R
            int sg = ((src[srcX] & 0xff00) >> 8);   //G
            int sb = src[srcX] & 0xff;              //B
            if (ix >= 0 && ix <= graphWidth && iy >= 0 && iy <= graphHeight && dstX <= graphWidth * graphHeight)
            {
                dstX = (ix + picture_x) + (iy + picture_y) * graphWidth; //在显存里像素的角标
                int dr = ((dst[dstX] & 0xff0000) >> 16);
                int dg = ((dst[dstX] & 0xff00) >> 8);
                int db = dst[dstX] & 0xff;
                draw[dstX] = ((sr * sa / 255 + dr * (255 - sa) / 255) << 16)  //公式: Cp=αp*FP+(1-αp)*BP  ; αp=sa/255 , FP=sr , BP=dr
                    | ((sg * sa / 255 + dg * (255 - sa) / 255) << 8)         //αp=sa/255 , FP=sg , BP=dg
                    | (sb * sa / 255 + db * (255 - sa) / 255);              //αp=sa/255 , FP=sb , BP=db
            }
        }
    }
}

// 适用于 y <0 以及x<0的任何情况
void putimagePNG2(int x, int y, IMAGE* picture) {
    IMAGE imgTmp;
    if (y < 0) {
        SetWorkingImage(picture);
        getimage(&imgTmp, 0, -y,
            picture->getwidth(), picture->getheight() + y);
        SetWorkingImage();
        y = 0;
        picture = &imgTmp;
    }

    if (x < 0) {
        SetWorkingImage(picture);
        getimage(&imgTmp, -x, 0, picture->getwidth() + x, picture->getheight());
        SetWorkingImage();
        x = 0;
        picture = &imgTmp;
    } 

    putimagePNG(x, y, picture);
}

// 适用于 y <0 以及y>0的任何情况
void putimagePNG2(int x, int y, int winWidth, IMAGE* picture) {
    IMAGE imgTmp;
    if (y < 0) {
        SetWorkingImage(picture);
        getimage(&imgTmp, 0, -y,
            picture->getwidth(), picture->getheight() + y);
        SetWorkingImage();
        y = 0;
        picture = &imgTmp;
    }

    if (x < 0) {
        SetWorkingImage(picture);
        getimage(&imgTmp, -x, 0, picture->getwidth() + x, picture->getheight());
        SetWorkingImage();
        x = 0;
        picture = &imgTmp;
    }
    else if (x >= winWidth) {
        return;
    }
    else if (x > winWidth-picture->getwidth()) {
        SetWorkingImage(picture);
        getimage(&imgTmp, 0, 0, winWidth - x, picture->getheight());
        SetWorkingImage();
        picture = &imgTmp;
    }

    putimagePNG(x, y, picture);
}

//设A[x01,y01,x02,y02]  B[x11,y11,x12,y12].
bool rectIntersect(int x01, int y01, int x02, int y02,
    int x11, int y11, int x12, int y12)
{
    int zx = abs(x01 + x02 - x11 - x12);
    int x = abs(x01 - x02) + abs(x11 - x12);
    int zy = abs(y01 + y02 - y11 - y12);
    int y = abs(y01 - y02) + abs(y11 - y12);
    return  (zx <= x && zy <= y);
}

void  preLoadSound(const char* name) {
    char cmd[512];
    sprintf_s(cmd, sizeof(cmd), "open %s alias %s-1", name, name);
    mciSendString(cmd, 0, 0, 0);
    sprintf_s(cmd, sizeof(cmd), "open %s alias %s-2", name, name);
    mciSendString(cmd, 0, 0, 0);
}

void  playSound(const char* name) {
    static int index = 1;
    char cmd[512];

    if (index == 1) {
        sprintf_s(cmd, sizeof(cmd), "play %s-1", name);
        mciSendString(cmd, 0, 0, 0);
        sprintf_s(cmd, sizeof(cmd), "close %s-2", name);
        mciSendString(cmd, 0, 0, 0);
        sprintf_s(cmd, sizeof(cmd), "open %s alias %s-2", name, name);
        mciSendString(cmd, 0, 0, 0);
        index++;
    }
    else if (index == 2) {
        sprintf_s(cmd, sizeof(cmd), "play %s-2", name);
        mciSendString(cmd, 0, 0, 0);
        sprintf_s(cmd, sizeof(cmd), "close %s-1", name);
        mciSendString(cmd, 0, 0, 0);
        sprintf_s(cmd, sizeof(cmd), "open %s alias %s-1", name, name);
        mciSendString(cmd, 0, 0, 0);
        index = 1;
    }
}

void drawBloodBar(int x, int y, int width, int height, int lineWidth, int boardColor, int emptyColor, int fillColor, float percent) {
    LINESTYLE lineStyle;
    getlinestyle(&lineStyle);
    int lineColor = getlinecolor();
    int fileColor = getfillcolor();

    if (percent < 0) {
        percent = 0;
    }

    setlinecolor(BLUE);
    setlinestyle(PS_SOLID | PS_ENDCAP_ROUND, lineWidth);
    setfillcolor(emptyColor);
    fillrectangle(x, y, x + width, y + height);
    setlinestyle(PS_SOLID | PS_ENDCAP_FLAT, 0);
    setfillcolor(fillColor);
    setlinecolor(fillColor);
    if (percent > 0) {
        fillrectangle(x + 0.5 * lineWidth, y + lineWidth * 0.5, x + width * percent, y + height - 0.5 * lineWidth);
    }
    
    setlinecolor(lineColor);
    setfillcolor(fillColor);
    setlinestyle(&lineStyle);
}

        4.可执行文件



#include<stdio.h>
#include<graphics.h>  //图形库
#include"tools.h"
#include<conio.h>  //kbhit
#include<vector> //长度可变数组   C++

using namespace std; //声明命名空间 C++
#define WIN_SCORE 15

#define WIN_WIDTH 1012  //窗口宽度
#define WIN_HEIGHT 396  //窗口长度
#define OBSTACLE_COUNT 20 //障碍物总数

IMAGE imgBgs[3];   //背景图片3张
int bgX[3]; //背景图片的X坐标
int bgSpeed[3] = { 1,2,4 }; //背景移动速度

IMAGE imgHeros[12]; //玩家图片12张
int heroX; //玩家的x坐标
int heroY; //玩家的y坐标
int heroIndex; //玩家奔跑的图片帧序号

bool heroJump; // 表示玩家正在跳跃

int jumpHeighMax; //跳跃最大高度
int heroJumpOff; //偏移量
int update;//表示是否需要马上刷新画面

//IMAGE imgTortoise; //小乌龟
//int torToiseX; //小乌龟的水平坐标
//int torToiseY; //小乌龟的垂直坐标
//bool torToiseExist;//当前窗口是否有小乌龟

int heroBlood; //初始化血量
int score; //分数
#define MAX_SCORE 0 // 定义初始接受最高分

//障碍物
 typedef enum {
    TORTOISE, //乌龟0
    LION, //狮子
    HOOK1,//柱子1
    HOOK2,
    HOOK3,
    HOOK4,
    OBSTACLE_TYPE_COUNT  //6
}obstacle_type;


 vector<vector<IMAGE>>obstacleImgs; 
 //IMAGEobstacleImgs[3][5]   存放所以障碍物的各个图片  C++语言
 
 //障碍物属性
typedef struct obstacle {
    int type;//障碍物类型 
    int x, y; //障碍物的坐标
    int imgIndex; //当前显示的图片的序号
    int speed; //速度
    int power; //杀伤力
    bool exist; //是否存在
    bool hited; //表示是否已经发生碰撞
    bool passed; //表示是否已经被通过
}obstacle_t;

int lastObsIndex;//上个障碍物的序号
obstacle_t obstacles[OBSTACLE_COUNT]; //障碍物池

IMAGE imgHeroDown[2];//下蹲素材
bool heroDown; //表示玩家是否处于下蹲状态

IMAGE imgSZ[10];

//游戏初始化
void init() {
    //创建游戏窗口
    initgraph(WIN_WIDTH, WIN_HEIGHT);

    //加载背景资源
    char name[64];
    for (int i = 0; i < 3; i++) {
        //"res/bg001.png"      "res/bg002.png"      "res/bg003.png"
        sprintf(name, "res/bg%03d.png",i+1);//%03宽度占三位
        loadimage(&imgBgs[i], name);
        bgX[i] = 0;
    }
   
    //加载Hero奔跑的图片帧素材
    for (int i = 0; i < 12; i++) {
        //"res/hero1.png"..."res/hero12.png"
        sprintf(name, "res/hero%d.png", i + 1);
        loadimage(&imgHeros[i], name);
    }

    //设置玩家的初始化位置
    heroX = WIN_WIDTH * 0.5 - imgHeros[0].getwidth() * 0.5;
    heroY = 345 - imgHeros[0].getheight();
    heroIndex = 0;

    heroJump = false; //初始化跳跃开关
    jumpHeighMax = 345 - imgHeros[0].getheight() - 120;
    heroJumpOff = -4;
    update = true;

    //加载小乌龟素材
   /* loadimage(&imgTortoise, "res/t1.png");
    torToiseExist = false;
    torToiseY = 345 - imgTortoise.getheight()+5;*/
    IMAGE imgTort;
    loadimage(&imgTort, "res/t1.png");
    vector<IMAGE>imgTortArray; //定义一个数组
    imgTortArray.push_back(imgTort); //添加图片
    obstacleImgs.push_back(imgTortArray);//放进二维数组
    
    //添加狮子
    IMAGE imgLion;
    vector<IMAGE>imgLionArray;
    for (int i = 0; i < 6; i++) {
        sprintf(name, "res/p%d.png", i + 1);
        loadimage(&imgLion, name);
        imgLionArray.push_back(imgLion);
    }
    obstacleImgs.push_back(imgLionArray);

    //初始化障碍物池
    for (int i = 0; i < OBSTACLE_COUNT; i++) {
        obstacles[i].exist = false;
    }

    //加载下蹲素材
    loadimage(&imgHeroDown[0], "res/d1.png");
    loadimage(&imgHeroDown[1], "res/d2.png");
    heroDown = false;

    IMAGE imgH;
    //添加柱子
    for (int i = 0; i < 4; i++) {
        vector<IMAGE>imgHookArray;
        sprintf(name,"res/h%d.png", i + 1);
        loadimage(&imgH, name, 63, 260, true);
        imgHookArray.push_back(imgH);
        obstacleImgs.push_back(imgHookArray);

    }
    heroBlood = 100;

    //预加载音效
    preLoadSound("res/hit.mp3");//解决第一次碰撞没声效

    //开启音乐
    mciSendString("play res/bg.mp3 repeat", 0, 0, 0);
    lastObsIndex = -1;//上次障碍物序号为-1
    score = 0;//分数初始化

    //加载数字图片
    for (int i = 0; i < 10; i++) {
        sprintf(name, "res/sz/%d.png", i);
        loadimage(&imgSZ[i], name);
    }
}

//创建障碍物
void createObstacle() {
    int i;
    for (i = 0; i < OBSTACLE_COUNT; i++) {
        if (obstacles[i].exist == false) {
            break;
        }
    }
    if (i >= OBSTACLE_COUNT) {
        return;
    }

    obstacles[i].exist = true;
    obstacles[i].hited = false;
    obstacles[i].imgIndex = 0;
    //obstacles[i].type = (obstacle_type)(rand() % OBSTACLE_TYPE_COUNT);
    obstacles[i].type = (obstacle_type)(rand() % 3);

    if (lastObsIndex >= 0 && obstacles[lastObsIndex].type >= HOOK1 && //解决死亡障碍
            obstacles[lastObsIndex].type <= HOOK4 && obstacles[i].type == LION && obstacles[lastObsIndex].x > (WIN_WIDTH - 500)) {
        obstacles[i].type = TORTOISE;
    }

    lastObsIndex = i;//更新障碍物类型
    if (obstacles[i].type == HOOK1) {
        obstacles[i].type +=rand()%4;  //0..3
    }
    obstacles[i].x = WIN_WIDTH;
    obstacles[i].y = 345 + 5 - obstacleImgs[obstacles[i].type][0].getheight();
    if (obstacles[i].type == TORTOISE) {
        obstacles[i].speed = 0;
        obstacles[i].power = 10;
    }
    else if (obstacles[i].type == LION) {
        obstacles[i].speed = 4;
        obstacles[i].power = 20;
    }
    else if (obstacles[i].type >= HOOK1&&obstacles[i].type<=HOOK4) {
        obstacles[i].speed = 0;
        obstacles[i].power = 20;
        obstacles[i].y = 0;
    }
    obstacles[i].passed = false;
}

//碰撞检测
void  checkHit() {
    for (int i = 0; i < OBSTACLE_COUNT; i++) {
        if (obstacles[i].exist&&obstacles[i].hited ==false) {
            int a1x, a1y, a2x, a2y;
            int off = 30;//压缩一下照片大小,偏移量
            if (!heroDown) {//非下蹲
                a1x = heroX+off;
                a1y = heroY + off;
                a2x = heroX + imgHeros[heroIndex].getwidth() - off;
                a2y = heroY + imgHeros[heroIndex].getheight();
            }
            else {//下蹲
                a1x = heroX + off;
                a1y = 345 - imgHeroDown[heroIndex].getheight();
                a2x = heroX + imgHeroDown[heroIndex].getwidth() - off;
                a2y = 345;
            }
            //障碍物
            IMAGE img = obstacleImgs[obstacles[i].type][obstacles[i].imgIndex];
            int b1x = obstacles[i].x + off;
            int b1y = obstacles[i].y + off;
            int b2x = obstacles[i].x + img.getwidth() - off;
            int b2y = obstacles[i].y+ img.getheight()-10;
            if (rectIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y)) {//判断是否碰撞
                heroBlood -= obstacles[i].power;
                printf("血量剩余%d\n", heroBlood);
                playSound("res/hit.mp3");
                obstacles[i].hited = true;
            }

        }
    }
}

void fly() {
    for (int i = 0; i < 3; i++) {
        bgX[i] -= bgSpeed[i];
        if (bgX[i] < -WIN_WIDTH) {//小于窗口的宽度
            bgX[i] = 0;
        }
    }
    //实现跳跃
    if (heroJump) {
        if (heroY < jumpHeighMax) {
            heroJumpOff = 4;
        }

        heroY += heroJumpOff;
        if (heroY > 345 - imgHeros[0].getheight()) {
            heroJump = false;
            heroJumpOff = -4; //再次初始化为-4
        }
    }
    else if (heroDown) {
        static int count = 0;//下蹲保持帧率
        int delays[2] = { 8,30 };//2个图片保持的帧度
        count++;
        if (count >= delays[heroIndex]) {
            count = 0;
            heroIndex++;
            if (heroIndex >= 2) {
                heroIndex = 0;
                heroDown = false;
            }
        }
    }
    else {//不跳跃不下蹲
        heroIndex = (heroIndex + 1) % 12;
    }

    //创建障碍物
    static int frameCount = 0;
    static int enemyFre = 50; //频度
    frameCount++;
    if (frameCount > enemyFre) {
        frameCount = 0;
        //if (!torToiseExist) {
        //    torToiseExist = true;
        //    torToiseX = WIN_WIDTH;
        //    enemyFre = 200+ rand() % 300;//200...500
        //} 
        enemyFre = 80 + rand() % 50;//80...129
        createObstacle();
       
    }
    //if (torToiseExist) {
    //    torToiseX -= bgSpeed[2];
    //    if (torToiseX < -imgTortoise.getwidth()) {
    //        torToiseExist = false;
    //    }
    //}
    

    //更新所有障碍物的目标
    for (int i = 0; i < OBSTACLE_COUNT; i++) {
        if (obstacles[i].exist) {
            obstacles[i].x -= obstacles[i].speed+bgSpeed[2];//速度加草坪的速度
            if (obstacles[i].x < -obstacleImgs[obstacles[i].type][0].getwidth() * 2) {
                obstacles[i].exist = false;
            }

            int len = obstacleImgs[obstacles[i].type].size();
            obstacles[i].imgIndex = (obstacles[i].imgIndex + 1) % len;//更改图片索引
        }
    }
    
    //玩家和障碍物的“碰撞检测”处理
    checkHit();
}


//渲染“游戏背景”
void updateBg() {

    putimagePNG2(bgX[0], 0, &imgBgs[0]);
    putimagePNG2(bgX[1], 119, &imgBgs[1]);
    putimagePNG2(bgX[2], 330, &imgBgs[2]);
}

//玩家跳跃
void jump() {
    heroJump = true;
    update = true;
}

//玩家下蹲
void down() {
    update = true;
    heroDown = true;
    heroIndex = 0;
}

//处理用户按键的输入
void keyEvent() {
    char ch;
    if (kbhit()) {//如果按键按下,_kbhit()返回true
        
        //scanf("%c", &c);//会直接阻塞程序的执行
        ch = _getch(); //_getch()不需要按下回车即可直接读取
        if (ch == ' ') {
            jump();
        }
        else if (ch == 'a') {
            down();
        }
    }
    

}

//渲染
void updateEnemy() {
    //渲染小乌龟
    /*if (torToiseExist) {
        putimagePNG2(torToiseX, torToiseY, WIN_WIDTH,&imgTortoise);
    }*/
    for (int i = 0; i < OBSTACLE_COUNT; i++) {
        if (obstacles[i].exist) {
            putimagePNG2(obstacles[i].x, obstacles[i].y,WIN_WIDTH,&obstacleImgs[obstacles[i].type][obstacles[i].imgIndex]);
        }
    }

}

//更新玩家
void updateHero() {
    if (!heroDown) {
        putimagePNG2(heroX, heroY, &imgHeros[heroIndex]);
    }
    else {

        int y = 345 - imgHeroDown[heroIndex].getheight();
        putimagePNG2(heroX, y, &imgHeroDown[heroIndex]);
    }
   
}

//渲染血条
void updateBloodBar() {
    drawBloodBar(10, 10, 200, 10, 2, BLUE, DARKGRAY, RED, heroBlood / 100.0);//比例
}

//检查结束
void checkOver() {
    if (heroBlood <= 0) {
        loadimage(0, "res/over.png");
        FlushBatchDraw();//刷新
        mciSendString("stop res/bg.mp3", 0, 0, 0);
        system("pause"); //用户按任意键继续

        //暂停之后,充币复活,或者直接开始下一局
      /*  heroBlood = 100;
        score = 0;
        mciSendString("play res/bg.mp3 repeat",0, 0,0);*/
        init();//调用,使游戏初始化
    } 
   
}


//检查得分
void checkScore() {
    for (int i = 0; i < OBSTACLE_COUNT; i++) {
        if (obstacles[i].hited == false && obstacles[i].exist && obstacles[i].passed == false
            && obstacles[i].x + obstacleImgs[obstacles[i].type][0].getwidth() < heroX) {
            score++;
            obstacles[i].passed = true;
        }
    }
    // 读取宏的值
    FILE* fp;
    int macro_score;
    fp = fopen("macro.txt", "r");
    if (fp != NULL) {
        fscanf(fp, "%d", &macro_score);
        fclose(fp);
    }
    else {
        macro_score = MAX_SCORE;
    }

    
    // 判断并更新宏
    if (score > macro_score) {
        
        macro_score = score;
        fp = fopen("macro.txt", "w");
        if (fp != NULL) {
            fprintf(fp, "%d", macro_score);
            fclose(fp);
        }
    }
    
    }
   
//显示分数
void updateScore() {
    //50 =>"50"      '5'    '5'-'0'= 5
    char str[8];
    sprintf(str, "%d", score);

    int x = 20;
    int y = 25;
    for (int i = 0; str[i]; i++) {
        int sz = str[i] - '0';
        putimagePNG(x, y, &imgSZ[sz]);
        x += imgSZ[sz].getwidth() + 5;
    }
}

//检查游戏胜利
void checkWin() {
    if (score >= WIN_SCORE) {
        FlushBatchDraw();//刷新
        mciSendString("play res/win.mp3", 0, 0, 0);
        Sleep(1000);
        loadimage(0, "res/win.png");
        FlushBatchDraw();
        mciSendString("stop res/bg.mp3", 0, 0, 0);
        system("pause");

        init();

    }
}
int main(void) {
    init();

    //显示初始画面
    loadimage(0, "res/over.png");
    system("pause");
    int timer = 0;
    while (1) {
        keyEvent();
        timer += getDelay(); //调用间隔
        if (timer > 30) {
            timer = 0;
            update = true;
           
        }

        if (update) {
            update = false;
            BeginBatchDraw();
            updateBg();
            //putimagePNG2(heroX, heroY, &imgHeros[heroIndex]);
            updateHero();
            updateEnemy();
            updateBloodBar();
            updateScore();
            checkWin();
            EndBatchDraw();
            checkOver();
            checkScore();
            
            fly();
       }

        //Sleep(5);//休眠 按键输入不响应

    } 
   
    system("pause");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/2201_75443644/article/details/130823874