能帮到你的话,就给个赞吧 😘
util.h
#pragma once
#include <graphics.h>
#include "camera.h"
void flipImage(IMAGE* src, IMAGE* dst);
void putImageAlpha(int x, int y, IMAGE* img); //图像绘制(透明度)
//裁剪任意位置的图并显示
//在(dst_x, dst_y) 处 显示 (src_x, src_y), w, h 的 图
void putImageAlpha(int dst_x, int dst_y, int width, int height, IMAGE* img, int src_x, int src_y);
void putLine(int x1, int y1, int x2, int y2);
util.cpp
#include "util.h"
#pragma comment(lib, "MSIMG32.LIB") //AlphaBlend
void flipImage(IMAGE* src, IMAGE* dst){
int height = src->getheight();
int width = src->getwidth();
Resize(dst, width, height);
auto srcPixels = GetImageBuffer(src);
auto dstPixels = GetImageBuffer(dst);
for (int h = 0; h < height; h++)
for (int w = 0; w < width; w++)
dstPixels[h * width + w] = srcPixels[h * width + width - 1 - w];
}
void putImageAlpha(int x, int y, IMAGE* img) {
int w = img->getwidth();
int h = img->getheight();
auto cameraX = Camera::getCamera().getPostion().x;
auto cameraY = Camera::getCamera().getPostion().y;
AlphaBlend(GetImageHDC(nullptr), x - cameraX, y - cameraY, w, h,
GetImageHDC(img), 0, 0, w, h, { AC_SRC_OVER,0,255, AC_SRC_ALPHA });
}
//在(dst_x, dst_y) 处 显示 (src_x, src_y), w, h 的 图
void putImageAlpha(int dst_x, int dst_y, int width, int height, IMAGE* img,int src_x, int src_y){
int w = width;
int h = height;
//将(src_x, src_y), w, h 的图像 复制到 (dst_x, dst_y)处
AlphaBlend(GetImageHDC(GetWorkingImage()), dst_x, dst_y, w, h,
GetImageHDC(img), src_x, src_y, w, h, { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA });
}
void putLine(int x1, int y1, int x2, int y2){
auto cameraX = Camera::getCamera().getPostion().x;
auto cameraY = Camera::getCamera().getPostion().y;
line(x1 - cameraX, y1 - cameraY, x2 - cameraX, y2 - cameraY);
}
platform.h
#pragma once
#include <graphics.h>
#include "camera.h"
#include "util.h"
extern bool isDebug;
class Platform {
//碰撞箱为一条直线
struct CollisionShape{
float y; //线的高度
float left, right; //线的左右端点
};
public:
//渲染数据
IMAGE* img = nullptr;
POINT renderPos = { 0 };
//碰撞数据
CollisionShape shape; //平台碰撞箱
public:
void render() const;
};
platform.cpp
#include "platform.h"
void Platform::render() const{
putImageAlpha(renderPos.x, renderPos.y, img);
if (isDebug) {
setlinecolor(RGB(255, 0, 0));
putLine(shape.left, shape.y, shape.right, shape.y);
}
}
main.cpp
#include <Windows.h> //windows要放在graphics之前
#include <graphics.h>
#include "menuScene.h"
#include "gameScene.h"
#include "selectorScene.h"
#include "sceneManager.h"
#include "util.h"
#include "atlas.h"
#include "platform.h"
#include <iostream>
using namespace std;
#pragma comment(lib, "Winmm.lib") //mciSendString
bool isDebug = false;
IMAGE imgMenuBackground;
IMAGE imgVS; //VS艺术字
IMAGE img1P; //文本
IMAGE img2P;
IMAGE img1PDesc; //键位描述
IMAGE img2PDesc;
IMAGE imgGraveStoneLeft; //向左墓碑
IMAGE imgGraveStoneRight;
IMAGE imgSelectorTip; //选择提示
IMAGE imgSelectorBackground;
IMAGE img1PSelectorButtonIdleLeft; //1P向左选择按钮默认
IMAGE img1PSelectorButtonIdleRight;
IMAGE img1PSelectorButtonDownLeft;
IMAGE img1PSelectorButtonDownRight; //1P向左选择按钮按下
IMAGE img2PSelectorButtonIdleLeft;
IMAGE img2PSelectorButtonIdleRight;
IMAGE img2PSelectorButtonDownLeft;
IMAGE img2PSelectorButtonDownRight;
IMAGE imgPeaShooterSelectorBackgroundLeft; //豌豆向左选择界面
IMAGE imgPeaShooterSelectorBackgroundRight;
IMAGE imgSunFlowerSelectorBackgroundLeft; //向日葵向左选择界面
IMAGE imgSunFlowerSelectorBackgroundRight;
IMAGE imgSky; //天空
IMAGE imgHills; //山脉
IMAGE imgLargePlatform; //平台
IMAGE imgSmallPlatform;
IMAGE img1PCursor;
IMAGE img2PCursor;
Atlas atlasPeaShooterIdleLeft; //豌豆向左
Atlas atlasPeaShooterIdleRight;
Atlas atlasPeaShooterRunLeft;
Atlas atlasPeaShooterRunRight;
Atlas atlasPeaShooterAttackExLeft; //豌豆向左特殊攻击
Atlas atlasPeaShooterAttackExRight;
Atlas atlasPeaShooterDieLeft; //向左死亡
Atlas atlasPeaShooterDieRight;
Atlas atlasSunFlowerIdleLeft; //向日葵
Atlas atlasSunFlowerIdleRight;
Atlas atlasSunFlowerRunLeft;
Atlas atlasSunFlowerRunRight;
Atlas atlasSunFlowerAttackExLeft;
Atlas atlasSunFlowerAttackExRight;
Atlas atlasSunFlowerDieLeft;
Atlas atlasSunFlowerDieRight;
IMAGE imgPea; //豌豆
Atlas atlasPeaBreak;
Atlas atlasSun;
Atlas atlasSunExplode; //太阳爆炸
Atlas atlasSunEX; //特殊动画
Atlas atlasSunEXExplode; //特殊爆炸
Atlas atlasSunText; //文本动画
Atlas atlasRunEffect; //奔跑特效
Atlas atlasJumpEffect;
Atlas atlasLandEffect;
IMAGE img1PWinner; //1P获胜文本
IMAGE img2PWinner;
IMAGE imgWinnerBar; //获胜背景
IMAGE imgPeaShooterAvatar; //豌豆头像
IMAGE imgSunFlowerAvatar; //向日葵头像
//场景与场景管理器互相引用
Scene* menuScene = new MenuScene;
Scene* gameScene = new GameScene;
Scene* selectorScene = new SelectorScene;
SceneManager sceneManager;
vector<Platform> platforms;
void flipAtlas(Atlas& src, Atlas& dst) {
dst.clear();
for (int i = 0; i < src.getSize(); i++) {
IMAGE img;
flipImage(src.getImage(i), &img);
dst.addImage(img);
}
}
void loadResources() {
//加载字体
//将 IPix.ttf" 加载到系统字体中,并将其设置为私有字体。
AddFontResourceEx(_T("resources/IPix.ttf"), FR_PRIVATE, nullptr);
//加载图片
loadimage(&imgMenuBackground, _T("resources/menu_background.png"));
loadimage(&imgVS, _T("resources/VS.png"));
loadimage(&img1P, _T("resources/1P.png"));
loadimage(&img2P, _T("resources/2P.png"));
loadimage(&img1PDesc, _T("resources/1P_desc.png"));
loadimage(&img2PDesc, _T("resources/2P_desc.png"));
loadimage(&imgGraveStoneRight, _T("resources/gravestone.png"));
flipImage(&imgGraveStoneRight, &imgGraveStoneLeft);
loadimage(&imgSelectorTip, _T("resources/selector_tip.png"));
loadimage(&imgSelectorBackground, _T("resources/selector_background.png"));
loadimage(&img1PSelectorButtonIdleRight, _T("resources/1P_selector_btn_idle.png"));
flipImage(&img1PSelectorButtonIdleRight, &img1PSelectorButtonIdleLeft);
loadimage(&img1PSelectorButtonDownRight, _T("resources/1P_selector_btn_down.png"));
flipImage(&img1PSelectorButtonDownRight, &img1PSelectorButtonDownLeft);
loadimage(&img2PSelectorButtonIdleRight, _T("resources/2P_selector_btn_idle.png"));
flipImage(&img2PSelectorButtonIdleRight, &img2PSelectorButtonIdleLeft);
loadimage(&img2PSelectorButtonDownRight, _T("resources/2P_selector_btn_down.png"));
flipImage(&img2PSelectorButtonDownRight, &img2PSelectorButtonDownLeft);
loadimage(&imgPeaShooterSelectorBackgroundRight, _T("resources/peashooter_selector_background.png"));
flipImage(&imgPeaShooterSelectorBackgroundRight, &imgPeaShooterSelectorBackgroundLeft);
loadimage(&imgSunFlowerSelectorBackgroundRight, _T("resources/sunflower_selector_background.png"));
flipImage(&imgSunFlowerSelectorBackgroundRight, &imgSunFlowerSelectorBackgroundLeft);
loadimage(&imgSky, _T("resources/sky.png"));
loadimage(&imgHills, _T("resources/hills.png"));
loadimage(&imgLargePlatform, _T("resources/platform_large.png"));
loadimage(&imgSmallPlatform, _T("resources/platform_small.png"));
loadimage(&img1PCursor, _T("resources/1P_cursor.png"));
loadimage(&img2PCursor, _T("resources/2P_cursor.png"));
//豌豆射手
atlasPeaShooterIdleRight.loadImages(_T("resources/peashooter_idle_%d.png"), 9);
flipAtlas(atlasPeaShooterIdleRight, atlasPeaShooterIdleLeft);
atlasPeaShooterRunRight.loadImages(_T("resources/peashooter_run_%d.png"), 5);
flipAtlas(atlasPeaShooterRunRight, atlasPeaShooterRunLeft);
atlasPeaShooterAttackExRight.loadImages(_T("resources/peashooter_attack_ex_%d.png"), 3);
flipAtlas(atlasPeaShooterAttackExRight, atlasPeaShooterAttackExLeft);
atlasPeaShooterDieRight.loadImages(_T("resources/peashooter_die_%d.png"), 4);
flipAtlas(atlasPeaShooterDieRight, atlasPeaShooterDieLeft);
//向日葵
atlasSunFlowerIdleRight.loadImages(_T("resources/sunflower_idle_%d.png"), 8);
flipAtlas(atlasSunFlowerIdleRight, atlasSunFlowerIdleLeft);
atlasSunFlowerRunRight.loadImages(_T("resources/sunflower_run_%d.png"), 5);
flipAtlas(atlasSunFlowerRunRight, atlasSunFlowerRunLeft);
atlasSunFlowerAttackExRight.loadImages(_T("resources/sunflower_attack_ex_%d.png"), 9);
flipAtlas(atlasSunFlowerAttackExRight, atlasSunFlowerAttackExLeft);
atlasSunFlowerDieRight.loadImages(_T("resources/sunflower_die_%d.png"), 2);
flipAtlas(atlasSunFlowerDieRight, atlasSunFlowerDieLeft);
loadimage(&imgPea, _T("resources/pea.png"));
atlasPeaBreak.loadImages(_T("resources/pea_break_%d.png"), 3);
atlasSun.loadImages(_T("resources/sun_%d.png"), 5);
atlasSunExplode.loadImages(_T("resources/sun_explode_%d.png"), 5);
atlasSunEX.loadImages(_T("resources/sun_ex_%d.png"), 5);
atlasSunEXExplode.loadImages(_T("resources/sun_ex_explode_%d.png"), 5);
atlasSunText.loadImages(_T("resources/sun_text_%d.png"), 6);
atlasRunEffect.loadImages(_T("resources/run_effect_%d.png"), 4);
atlasJumpEffect.loadImages(_T("resources/jump_effect_%d.png"), 5);
atlasLandEffect.loadImages(_T("resources/land_effect_%d.png"), 2);
loadimage(&img1PWinner, _T("resources/1P_winner.png"));
loadimage(&img2PWinner, _T("resources/2P_winner.png"));
loadimage(&imgWinnerBar, _T("resources/winnner_bar.png"));
loadimage(&imgPeaShooterAvatar, _T("resources/avatar_peashooter.png"));
loadimage(&imgSunFlowerAvatar, _T("resources/avatar_sunflower.png"));
//加载音乐
mciSendString(_T("open resources/bgm_game.mp3 alias bgmGame"), nullptr, 0, nullptr);
mciSendString(_T("open resources/bgm_menu.mp3 alias bgmMenu"), nullptr, 0, nullptr);
mciSendString(_T("open resources/pea_break_1.mp3 alias peaBreak1"), nullptr, 0, nullptr);
mciSendString(_T("open resources/pea_break_2.mp3 alias peaBreak2"), nullptr, 0, nullptr);
mciSendString(_T("open resources/pea_break_3.mp3 alias peaBreak3"), nullptr, 0, nullptr);
mciSendString(_T("open resources/pea_shoot_1.mp3 alias peaShoot1"), nullptr, 0, nullptr);
mciSendString(_T("open resources/pea_shoot_2.mp3 alias peaShoot2"), nullptr, 0, nullptr);
mciSendString(_T("open resources/pea_shoot_ex.mp3 alias peaShootEx"), nullptr, 0, nullptr);
mciSendString(_T("open resources/sun_explode.mp3 alias sunExplode"), nullptr, 0, nullptr);
mciSendString(_T("open resources/sun_explode_ex.mp3 alias sunExplodeEx"), nullptr, 0, nullptr);
mciSendString(_T("open resources/sun_text.mp3 alias sunText"), nullptr, 0, nullptr);
mciSendString(_T("open resources/ui_confirm.wav alias uiConfirm"), nullptr, 0, nullptr);
mciSendString(_T("open resources/ui_switch.wav alias uiSwitch"), nullptr, 0, nullptr);
mciSendString(_T("open resources/ui_win.wav alias uiWin"), nullptr, 0, nullptr);
}
int main() {
//加载资源
loadResources();
//初始化管理器
sceneManager.setSceneManager(menuScene);
ExMessage msg;
const int FPS = 1000 / 60;
initgraph(1280, 720, EW_SHOWCONSOLE); //EW_SHOWCONSOLE
//设置文本样式
//要在initgraph才能设置
settextstyle(28, 0, _T("IPix"));
setbkmode(TRANSPARENT);
BeginBatchDraw();
while (1) {
auto startTime = GetTickCount64();
//接收消息
if(peekmessage(&msg))
sceneManager.receiveInput(msg);
//管理器运行的时间
static auto managerLastTime = GetTickCount64();
auto managerCurrentTime = GetTickCount64();
sceneManager.update(managerCurrentTime - managerLastTime);
managerLastTime = managerCurrentTime;
cleardevice();
//渲染
sceneManager.render();
FlushBatchDraw();
//hertz
auto excutionTime = GetTickCount64() - startTime;
if (excutionTime < FPS)
Sleep(FPS - excutionTime);
}
EndBatchDraw();
//释放资源
delete menuScene;
delete gameScene;
}
gameScene.h
#pragma once
#include "scene.h"
#include "sceneManager.h"
#include "util.h"
#include "platform.h"
extern IMAGE imgSky; //天空
extern IMAGE imgHills; //山脉
extern IMAGE imgLargePlatform; //平台
extern IMAGE imgSmallPlatform;
extern SceneManager sceneManager;
extern std::vector<Platform> platforms;
class GameScene :public Scene {
public:
virtual void enter(); //场景进入——初始化所有场景对象
virtual void exit(); //退出
virtual void receiveInput(const ExMessage& msg); //输入
virtual void update(int runTimeMs); //场景更新——让场景运行的时间
virtual void render(); //渲染
private:
//天空山脉 世界坐标
POINT posImgSky = { 0 };
POINT posImgHills = { 0 };
};
gameScene.cpp
#include "gameScene.h"
#include <iostream>
#include "sceneManager.h"
void GameScene::enter(){
int xWindow = getwidth(), yWindow = getheight();
//窗口居中
posImgSky.x = (xWindow - imgSky.getwidth()) / 2,
posImgSky.y = (yWindow - imgSky.getheight()) / 2;
posImgHills.x = (xWindow - imgHills.getwidth()) / 2,
posImgHills.y = (yWindow - imgHills.getheight()) / 2;
//初始化平台
platforms.resize(4);
//large
auto& largePlatform = platforms[0];
largePlatform.img = &imgLargePlatform;
largePlatform.renderPos.x = 122, largePlatform.renderPos.y = 455;
//碰撞箱 一般 位于 渲染图内部偏上
largePlatform.shape.left = largePlatform.renderPos.x + 30,
largePlatform.shape.right = largePlatform.renderPos.x + largePlatform.img->getwidth() - 30,
largePlatform.shape.y = largePlatform.renderPos.y + 60;
//small1
auto& smallPlatform1 = platforms[1];
smallPlatform1.img = &imgSmallPlatform;
smallPlatform1.renderPos.x = 175, smallPlatform1.renderPos.y = 360;
smallPlatform1.shape.left = smallPlatform1.renderPos.x + 40,
smallPlatform1.shape.right = smallPlatform1.renderPos.x + smallPlatform1.img->getwidth() - 40,
smallPlatform1.shape.y = smallPlatform1.renderPos.y + smallPlatform1.img->getheight() / 2;
//small2
auto& smallPlatform2 = platforms[2];
smallPlatform2.img = &imgSmallPlatform;
smallPlatform2.renderPos.x = 855, smallPlatform2.renderPos.y = 360;
smallPlatform2.shape.left = smallPlatform2.renderPos.x + 40,
smallPlatform2.shape.right = smallPlatform2.renderPos.x + smallPlatform2.img->getwidth() - 40,
smallPlatform2.shape.y = smallPlatform2.renderPos.y + smallPlatform2.img->getheight() / 2;
//small3
auto& smallPlatform3 = platforms[3];
smallPlatform3.img = &imgSmallPlatform;
smallPlatform3.renderPos.x = 515, smallPlatform3.renderPos.y = 225;
smallPlatform3.shape.left = smallPlatform3.renderPos.x + 40,
smallPlatform3.shape.right = smallPlatform3.renderPos.x + smallPlatform3.img->getwidth() - 40,
smallPlatform3.shape.y = smallPlatform3.renderPos.y + smallPlatform3.img->getheight() / 2;
}
void GameScene::exit() {
}
void GameScene::receiveInput(const ExMessage& msg){
switch (msg.message){
case WM_KEYUP:
//q
if (msg.vkcode == 0x51)
isDebug = !isDebug;
break;
default:
break;
}
}
void GameScene::update(int runTimeMs){
}
void GameScene::render(){
putImageAlpha(posImgSky.x, posImgSky.y, &imgSky);
putImageAlpha(posImgHills.x, posImgHills.y, &imgHills);
for (const auto& platform : platforms)
platform.render();
if (isDebug) {
settextcolor(RGB(255, 0, 0));
outtextxy(15, 15, _T("调试模式已开启,按q关闭"));
}
}