按照这个写法,player在碰到star后并没有触发star的粒子特效,帮我修改仅展示修改部分代码// 粒子系统头文件 (ParticleSystem.h)
#pragma once
#include <graphics.h>
#include <vector>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <algorithm>
// 添加以下宏定义(方法1或方法2)
#ifndef GetAValue
#define GetAValue(rgb) ((rgb >> 24) & 0xFF) // 从COLORREF获取Alpha值
#endif
#ifndef RGBA
#define RGBA(r,g,b,a) ((COLORREF)((((a) & 0xff) << 24) | \
(((r) & 0xff) << 16) | \
(((g) & 0xff) << 8) | \
((b) & 0xff)))
#endif
// 粒子结构体
struct Particle {
float x, y; // 位置
float vx, vy; // 速度
float size; // 大小
float life; // 剩余生命周期 (0-1)
COLORREF color; // 颜色
float rotation; // 旋转角度
float rotationSpeed; // 旋转速度
};
// 粒子系统类
class StarParticleSystem {
private:
std::vector<Particle> particles;
IMAGE particleImg; // 粒子图像
bool initialized = false;
public:
StarParticleSystem() {
// 初始化随机种子
srand(static_cast<unsigned>(time(nullptr)));
}
// 初始化粒子图像
void initialize() {
if (initialized) return;
// 创建粒子图像:圆形渐变
particleImg.Resize(32, 32);
SetWorkingImage(&particleImg);
SetWorkingImage(&particleImg);
cleardevice();
// 创建渐变圆形
for (int r = 15; r >= 0; r--) {
int alpha = static_cast<int>(255 * (1.0f - r / 15.0f));
setfillcolor(RGBA(255, 255, 200, alpha)); // 使用RGBA宏
solidcircle(16, 16, r);
}
SetWorkingImage(NULL);
initialized = true;
}
// 在星星位置创建爆炸效果
void createStarExplosion(float centerX, float centerY, int count = 100) {
initialize(); // 确保已初始化
for (int i = 0; i < count; i++) {
Particle p;
p.x = centerX;
p.y = centerY;
// 随机方向 (向外扩散)
float angle = (rand() % 360) * 3.14159f / 180.0f;
float speed = 1.0f + (rand() % 10) / 5.0f;
p.vx = cos(angle) * speed;
p.vy = sin(angle) * speed;
// 随机大小 (5-20像素)
p.size = 5.0f + (rand() % 15);
// 随机生命周期 (0.5-1.5秒)
p.life = 0.5f + (rand() % 100) / 100.0f;
// 随机颜色 (黄色到金色)
int r = 255;
int g = 200 + (rand() % 55);
int b = 50 + (rand() % 100);
p.color = RGB(r, g, b);
// 旋转效果
p.rotation = rand() % 360;
p.rotationSpeed = -5.0f + (rand() % 10);
particles.push_back(p);
}
// 添加几个大型中心粒子
for (int i = 0; i < 5; i++) {
Particle p;
p.x = centerX;
p.y = centerY;
p.vx = (rand() % 10 - 5) / 5.0f;
p.vy = (rand() % 10 - 5) / 5.0f;
p.size = 20.0f + (rand() % 15);
p.life = 1.0f + (rand() % 50) / 100.0f;
p.color = RGB(255, 255, 200);
p.rotation = rand() % 360;
p.rotationSpeed = -5.0f + (rand() % 10);
particles.push_back(p);
}
}
// 更新所有粒子
void update() {
for (auto it = particles.begin(); it != particles.end(); ) {
// 更新位置
it->x += it->vx;
it->y += it->vy;
// 添加阻力效果
it->vx *= 0.98f;
it->vy *= 0.98f;
// 添加轻微重力
it->vy += 0.05f;
// 减少生命周期
it->life -= 0.02f;
// 更新旋转
it->rotation += it->rotationSpeed;
// 移除死亡的粒子
if (it->life <= 0) {
it = particles.erase(it);
}
else {
++it;
}
}
}
// 绘制所有粒子
void draw() {
for (auto& p : particles) {
// 计算透明度
int alpha = static_cast<int>(255 * p.life);
// 计算绘制位置
float drawX = p.x - p.size / 2;
float drawY = p.y - p.size / 2;
// 使用旋转和透明方式绘制粒子
putimage_rotate_alpha(drawX, drawY, &particleImg,
alpha, p.size, p.size, p.rotation);
}
}
// 清除所有粒子
void clear() {
particles.clear();
}
// 检查是否有活跃粒子
bool hasActiveParticles() const {
return !particles.empty();
}
private:
// 辅助函数:带旋转和透明度的图像绘制
void putimage_rotate_alpha(float x, float y, IMAGE* img, int alpha,
int width, int height, float rotation) {
// 创建临时图像
IMAGE tempImg;
tempImg.Resize(width, height);
SetWorkingImage(&tempImg);
cleardevice();
// 旋转并绘制到临时图像
DWORD* dst = GetImageBuffer(&tempImg);
DWORD* src = GetImageBuffer(img);
float centerX = width / 2.0f;
float centerY = height / 2.0f;
float sinRot = sin(rotation * 3.14159f / 180.0f);
float cosRot = cos(rotation * 3.14159f / 180.0f);
for (int dy = 0; dy < height; dy++) {
for (int dx = 0; dx < width; dx++) {
// 计算旋转后的位置
float srcX = centerX + (dx - centerX) * cosRot - (dy - centerY) * sinRot;
float srcY = centerY + (dx - centerX) * sinRot + (dy - centerY) * cosRot;
if (srcX >= 0 && srcX < img->getwidth() &&
srcY >= 0 && srcY < img->getheight()) {
int srcIdx = static_cast<int>(srcY) * img->getwidth() + static_cast<int>(srcX);
DWORD color = src[srcIdx];
// 应用透明度
BYTE a = (BYTE)((GetAValue(color) * alpha) / 255); // 使用GetAValue宏
color = (color & 0x00FFFFFF) | (a << 24);
dst[dy * width + dx] = color;
}
}
}
SetWorkingImage(NULL);
// 绘制临时图像到屏幕
HDC dstDC = GetImageHDC(NULL);
HDC srcDC = GetImageHDC(&tempImg);
BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
AlphaBlend(
dstDC, static_cast<int>(x), static_cast<int>(y), width, height,
srcDC, 0, 0, width, height,
bf
);
}
};
// 全局粒子系统实例
extern StarParticleSystem starParticles;#pragma once
#include <windows.h>
class Timer // 改进的延时
{
private:
LARGE_INTEGER clock;
LONGLONG lastClock;
int frequency;
public:
Timer()
{
QueryPerformanceFrequency(&clock);
frequency = (int)clock.QuadPart / 1000;
lastClock = 0;
}
void Sleep(int ms)
{
unsigned int c = ms * frequency;
if (lastClock == 0)
{
QueryPerformanceCounter(&clock);
lastClock = clock.QuadPart;
}
lastClock += c;
QueryPerformanceCounter(&clock);
if (clock.QuadPart > lastClock)
lastClock = clock.QuadPart;
else
{
do
{
::Sleep(1);
QueryPerformanceCounter(&clock);
} while (clock.QuadPart < lastClock);
}
}
};#include<graphics.h>
#include<conio.h>
#include<stdio.h>
#include <time.h>
#include "Timer.h"
#include <atomic>
#include <thread>
#include <windows.h>
#include <mmsystem.h>
#include <vector>
#include <string>
#include<cmath>
#pragma comment( lib, "MSIMG32.LIB")
#pragma comment(lib, "winmm.lib")
#include "lizi.h"
using namespace std;
#define WIDTH 1080
#define HEIGHT 600
StarParticleSystem starParticles;
atomic<bool> stopPlayback(false);
thread* mp3Thread = nullptr;
Timer timer;
clock_t gameStartTime = 0;
void playMP3(const char* filename) {
if (stopPlayback.load()) return;
char cmd[256] = { 0 };
sprintf_s(cmd, "open \"%s\" alias mp3", filename);
mciSendStringA(cmd, NULL, 0, NULL);
sprintf_s(cmd, "play mp3 repeat");
mciSendStringA(cmd, NULL, 0, NULL);
while (!stopPlayback.load()) {
if (_kbhit()) {
char key = _getch();
if (key == 'w' || GetAsyncKeyState(VK_UP)) {
PlaySoundA("music/jumpmusic.wav", NULL, SND_FILENAME | SND_ASYNC | SND_NODEFAULT);
}
}
this_thread::sleep_for(chrono::milliseconds(100));
}
sprintf_s(cmd, "close mp3");
mciSendStringA(cmd, NULL, 0, NULL);
}
void stopBackgroundMusic() {
if (!stopPlayback.load()) {
stopPlayback.store(true);
mciSendStringA("close mp3", NULL, 0, NULL);
}
}
enum PlayerStatus {
stillleft, stillright, walkleft, walkright,
jumpleft, jumpright, die
};
void transparentimage3(IMAGE* dstimg, int x, int y, IMAGE* srcimg) {
HDC dstDC = GetImageHDC(dstimg);
HDC srcDC = GetImageHDC(srcimg);
int w = srcimg->getwidth();
int h = srcimg->getheight();
BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
AlphaBlend(dstDC, x, y, w, h, srcDC, 0, 0, w, h, bf);
}
class Land {
public:
IMAGE im_land;
float land_width, land_height;
float x, left_x, top_y;
void initialize(int width = 400, int height = 80) {
loadimage(&im_land, _T("land1.png"), width, height);
land_height = im_land.getheight();
land_width = im_land.getwidth();
top_y = HEIGHT / 2;
}
void draw(float px, float py) {
transparentimage3(NULL, x - land_width / 2 - px, top_y - py - 10, &im_land);
///调试
setlinecolor(GREEN);
rectangle(x - land_width / 2 - px, top_y - py - 10,
x + land_width / 2 - px, top_y - py + land_height);
}
};
class Key {
public:
IMAGE im_key;
float x, y;
float width, height;
bool active;
void initialize() {
loadimage(&im_key, _T("money.png"), 35, 35);
width = im_key.getwidth();
height = im_key.getheight();
active = true;
}
void draw(float px, float py) {
if (active)
transparentimage3(NULL, x - px, y - py, &im_key);
}
bool checkCollision(float playerX, float playerY, float playerWidth, float playerHeight) {
if (!active) return false;
float playerRight = playerX + playerWidth;
float playerBottom = playerY + playerHeight;
float keyRight = x + width;
float keyBottom = y + height;
return (playerX < keyRight &&
playerRight > x &&
playerY < keyBottom &&
playerBottom > y);
}
};
class Enemy {
public:
IMAGE im_enemy;
float e_height, e_width;
float vx, vy;
float x, y;
float x_min, x_max;
float g;
bool isAlive;
bool isOnGround;
void initialize() {
loadimage(&im_enemy, _T("monster.png"), 40, 40);
e_height = im_enemy.getheight();
e_width = im_enemy.getwidth();
vy = 0;
g = 3; // 减小重力
isOnGround = false;
isAlive = true;
}
void draw(float px, float py) {
if (isAlive) {
transparentimage3(NULL, x - e_width / 2 - px, y - e_height / 2 - py, &im_enemy);
}
}
void update(vector<Land>& lands) {
if (!isAlive) return;
// 水平移动
x += vx;
if (x > x_max || x < x_min) {
vx = -vx;
}
// 应用重力
vy += g;
y += vy;
// 检测与地面的碰撞
isOnGround = false;
for (auto& land : lands) {
float enemyBottom = y + e_height / 2;
float enemyLeft = x - e_width / 2;
float enemyRight = x + e_width / 2;
float landLeft = land.x - land.land_width / 2;
float landRight = land.x + land.land_width / 2;
float landTop = land.top_y;
// 检查是否在地面上方且垂直距离接近
if (enemyBottom >= landTop - 5 && enemyBottom <= landTop + 10 &&
enemyRight > landLeft && enemyLeft < landRight) {
y = landTop - e_height / 2; // 调整敌人位置到地面
vy = 0; // 重置垂直速度
isOnGround = true;
break;
}
}
}
};
class Scene {
public:
IMAGE im_bk;
IMAGE im_star;
IMAGE im_pan;
IMAGE victoryImg;;
IMAGE gameOverImg;
vector<Land> land;
vector<Enemy> enemies;
vector<Key> moneys;
float panX, panY;
float panWidth, panHeight;
void draw(float px, float py) {
// 修改背景绘制方式,使其随玩家移动
// 背景移动速度为玩家移动速度的一半
float bgOffsetX = px / 4; // 调整这个值可以改变背景移动速度
float bgOffsetY = py / 4; // 调整这个值可以改变背景移动速度
// 计算背景位置,确保不会超出边界
int bgX = -bgOffsetX;
int bgY = -bgOffsetY;
// 确保背景不会显示空白区域
if (bgX > 0) bgX = 0;
if (bgY > 0) bgY = 0;
if (bgX < WIDTH - im_bk.getwidth()) bgX = WIDTH - im_bk.getwidth();
if (bgY < HEIGHT - im_bk.getheight()) bgY = HEIGHT - im_bk.getheight();
putimage(bgX, bgY, &im_bk);
for (int i = 0; i < land.size(); i++) {
land[i].draw(px, py);
}
for (int i = 0; i < enemies.size(); i++) {
enemies[i].draw(px, py);
}
for (int i = 0; i < moneys.size(); i++) {
moneys[i].draw(px, py);
}
// 绘制星星(终点)
Land& lastLand = land[land.size() - 1];
float starX = lastLand.x - im_star.getwidth() / 2 - px;
float starY = lastLand.top_y - im_star.getheight()-30 - py;
transparentimage3(NULL, starX, starY, &im_star);
// 绘制底部的盘子(放在星星正下方)
float panX = lastLand.x - panWidth / 2 - px;
float panY = lastLand.top_y + 600 - py; // 在星星下方500像素处
transparentimage3(NULL, panX, panY, &im_pan);
}
void initialize() {
loadimage(&im_bk, _T("bk.jpg"), 1080, 800); // 依次导入各张背景图片
loadimage(&im_star, _T("star.png"), 40, 40);
loadimage(&im_pan, _T("pan.png"), 600, 100); // 加载盘子图片
loadimage(&victoryImg, _T("chip.png"), 300, 300); // 加载胜利结算图片
loadimage(&gameOverImg, _T("gameover.png"), WIDTH, HEIGHT); // 加载游戏结束图片
// 初始化盘子
panWidth = im_pan.getwidth();
panHeight = im_pan.getheight();
land.clear();
// 有序排列地面 - 阶梯式,确保不重叠
Land l1;
l1.initialize(400, 80); // 宽度400,高度80
l1.x = 200;
l1.top_y = HEIGHT - 100;
land.push_back(l1);
Land l2;
l2.initialize(300, 60);
l2.x = 700; // 从l1的右侧开始 (200 + 400/2 + 300/2 + 间隙)
l2.top_y = HEIGHT - 200;
land.push_back(l2);
Land l3;
l3.initialize(350, 70);
l3.x = 1100;
l3.top_y = HEIGHT - 150;
land.push_back(l3);
Land l4;
l4.initialize(300, 60);
l4.x = 1500;
l4.top_y = HEIGHT - 250;
land.push_back(l4);
Land l5;
l5.initialize(400, 80);
l5.x = 1900;
l5.top_y = HEIGHT - 100;
land.push_back(l5);
// 确定玩家初始位置(中心点)
float playerCenterX = land[0].x; // 玩家初始位置中心
float safeDistance = 200.0f; // 安全距离
enemies.clear();
for (int i = 0; i < 3; ++i) {
Enemy enemy;
enemy.initialize();
// 尝试找到安全位置
int attempts = 0;
bool positionSafe = false;
int idx = 0;
while (!positionSafe && attempts < 20) {
idx = rand() % land.size();
enemy.x = land[idx].x;
// 检查是否在安全距离外
float distance = fabs(enemy.x - playerCenterX);
positionSafe = (distance > safeDistance);
attempts++;
}
enemy.y = land[idx].top_y - enemy.e_height / 2;
enemy.x_min = land[idx].x - 100;
enemy.x_max = land[idx].x + 100;
enemy.vx = 2 + rand() % 3;
enemies.push_back(enemy);
}
moneys.clear();
for (int i = 0; i < 10; ++i) {
Key money;
money.initialize();
int idx = rand() % land.size();
money.x = land[idx].x + rand() % ((int)land[idx].land_width - 40);
money.y = land[idx].top_y - 50;
moneys.push_back(money);
}
}
void showGameOver() {
cleardevice();
transparentimage3(NULL, 0, 0, &gameOverImg);
FlushBatchDraw();
Sleep(3000); // 显示3秒
}
void showVictoryScreen(int score, double timeTaken) {
cleardevice();
// 绘制胜利结算图片
IMAGE ziImg;
loadimage(&ziImg, _T("zi.png"), 600, 200); // 假设zi图片大小为200x100
int chipX = (WIDTH - victoryImg.getwidth()) / 2;
int chipY = HEIGHT / 4;
transparentimage3(NULL, chipX, chipY, &victoryImg);
int ziX = chipX + (victoryImg.getwidth() - ziImg.getwidth()) / 2;
int ziY = chipY + (victoryImg.getheight() - ziImg.getheight()) / 2 - 180; // 向上偏移20像素
transparentimage3(NULL, ziX, ziY, &ziImg);
// 在图片下方显示分数
TCHAR buffer[100];
wsprintf(buffer, _T("得分: %d"), score);
setbkmode(TRANSPARENT);
settextcolor(WHITE);
settextstyle(36, 0, _T("宋体"));
outtextxy((WIDTH - textwidth(buffer)) / 2, chipY + victoryImg.getheight() + 20, buffer);
// 修复时间显示问题:使用sprintf_s转换浮点数
char timeBuffer[50];
sprintf_s(timeBuffer, "通关时间: %.2f 秒", timeTaken);
// 将char数组转换为TCHAR数组
TCHAR tcharTime[50];
#ifdef UNICODE
MultiByteToWideChar(CP_ACP, 0, timeBuffer, -1, tcharTime, 50);
#else
strcpy_s(tcharTime, timeBuffer);
#endif
outtextxy((WIDTH - textwidth(tcharTime)) / 2,
chipY + victoryImg.getheight() + 90,
tcharTime);
FlushBatchDraw();
Sleep(5000); // 显示5秒
}
void showLifeInfo(int lives) {
cleardevice();
setbkmode(TRANSPARENT);
settextcolor(WHITE);
settextstyle(50, 0, _T("宋体"));
IMAGE im_lives;
loadimage(&im_lives, _T("life.png"), 150, 150);
TCHAR buffer[100];
transparentimage3(NULL, WIDTH / 2 - 100, HEIGHT / 2 - 25, &im_lives);
wsprintf(buffer, _T(" X %d"), lives);
outtextxy(WIDTH / 2 + 90, HEIGHT / 2 + 20, buffer);
FlushBatchDraw();
Sleep(2000); // 显示2秒
}
};
Scene scene;
class Player {
public:
IMAGE im_now;
IMAGE im_stillleft;
IMAGE im_stillright;
IMAGE im_jumpleft;
IMAGE im_jumpright;
IMAGE im_walkright;
IMAGE im_walkleft;
PlayerStatus playerStatus;
float x_left, y_bottom;
float vx, vy;
float width, height;
float g;
float fallingG; // 自由落体时的重力加速度
int score = 0;
int lives = 3;
bool isWin = false; // 是否触碰到星星
bool isFalling = false; // 是否处于自由落体状态
void draw() {
transparentimage3(NULL, WIDTH / 2, HEIGHT / 2 - height, &im_now);
}
void initialize() {
loadimage(&im_stillleft, _T("kim_left.png"), 60, 80);
loadimage(&im_stillright, _T("kim_right.png"), 60, 80);
loadimage(&im_jumpleft, _T("kim_jumpleft.png"), 60, 80);
loadimage(&im_jumpright, _T("kim_jumpright.png"), 60, 80);
loadimage(&im_walkright, _T("kim_right.png"), 60, 80);
loadimage(&im_walkleft, _T("kim_left.png"), 60, 80);
playerStatus = stillright;
im_now = im_stillright;
width = im_stillright.getwidth();
height = im_stillright.getheight();
if (!scene.land.empty()) {
x_left = scene.land[0].x - width / 2;
y_bottom = scene.land[0].top_y;
}
else {
x_left = WIDTH / 2;
y_bottom = HEIGHT - 100;
}
vx = 15; // 水平速度
vy = 0;
g = 5;
fallingG = 0.4; // 自由落体时的重力加速度(更慢)
}
void update(float x, float y) {
x_left = x;
y_bottom = y;
}
void walkRight(Scene& scene) {
x_left += vx;
if (x_left < 0) x_left = 0;
if (isNotOnAllLands(scene.land, vy)) {
im_now = im_jumpright;
playerStatus = jumpright;
return;
}
if (playerStatus == jumpleft || playerStatus == jumpright) {
im_now = im_jumpright;
}
else {
playerStatus = walkright;
im_now = im_walkright;
}
}
void walkLeft(Scene& scene) {
if (isFalling) return; // 自由落体时不能移动
x_left -= vx;
if (x_left < 0) x_left = 0;
if (isNotOnAllLands(scene.land, vy)) {
im_now = im_jumpleft;
playerStatus = jumpleft;
return;
}
if (playerStatus == jumpleft || playerStatus == jumpright) {
im_now = im_jumpleft;
}
else {
playerStatus = walkleft;
im_now = im_walkleft;
}
}
void standstill() {
if (isFalling) return; // 自由落体时不能移动
if (playerStatus == stillleft || playerStatus == walkleft) {
im_now = im_stillleft;
}
else if (playerStatus == stillright || playerStatus == walkright) {
im_now = im_stillright;
}
}
void beginjump() {
if (isFalling) return; // 自由落体时不能移动
if (playerStatus != jumpleft && playerStatus != jumpright) {
if (playerStatus == walkleft || playerStatus == stillleft) {
im_now = im_jumpleft;
playerStatus = jumpleft;
}
else if (playerStatus == walkright || playerStatus == stillright) {
im_now = im_jumpright;
playerStatus = jumpright;
}
vy = -50;
}
}
bool isOnLand(Land& land, float ySpeed) {
float playerRight = x_left + width;
float playerBottom = y_bottom;
float playerTop = y_bottom - height; // 添加playerTop定义
float landLeft = land.x - land.land_width / 2;
float landRight = land.x + land.land_width / 2;
float landTop = land.top_y;
// 检查是否在地面上方且垂直距离接近
bool verticalOverlap = (playerBottom >= landTop - 10 && playerTop <= landTop + 10);
bool horizontalOverlap = (x_left < landRight && playerRight > landLeft);
if (verticalOverlap && horizontalOverlap) {
y_bottom = landTop; // 将玩家放在地面上
return true;
}
return false;
}
bool isNotOnAllLands(vector<Land>& lands, float speed) {
for (auto& land : lands) {
if (isOnLand(land, speed)) {
return false;
}
}
return true;
}
void updateKeycode(Scene& scene) {
// 应用重力
float currentG = isFalling ? fallingG : g;
vy += currentG;
y_bottom += vy; // 检测与地面的碰撞
bool onGround = false;
for (auto& land : scene.land) {
if (isOnLand(land, vy)) {
onGround = true;
vy = 0; // 重置垂直速度
// 落地后恢复行走状态
if (playerStatus == jumpleft) {
playerStatus = stillleft;
}
else if (playerStatus == jumpright) {
playerStatus = stillright;
}
break;
}
}
// 如果不在任何地面上且速度向下,保持跳跃状态
if (!onGround && vy > 0) {
if (playerStatus == stillleft || playerStatus == walkleft) {
playerStatus = jumpleft;
}
else if (playerStatus == stillright || playerStatus == walkright) {
playerStatus = jumpright;
}
}
}
bool stompEnemy(Enemy& enemy) {
if (!enemy.isAlive) return false;
float playerBottom = y_bottom;
float playerLeft = x_left;
float playerRight = x_left + width;
float enemyTop = enemy.y - enemy.e_height / 2;
float enemyLeft = enemy.x - enemy.e_width / 2;
float enemyRight = enemy.x + enemy.e_width / 2;
// 检查玩家是否在敌人上方
if (playerBottom <= enemyTop + 10 &&
playerRight > enemyLeft &&
playerLeft < enemyRight &&
vy > 0) {
enemy.isAlive = false; // 敌人死亡
vy = -15; // 玩家弹起
score += 100;
// 播放敌人死亡音效
PlaySoundA("music/monstermusic.wav", NULL, SND_FILENAME | SND_ASYNC | SND_NODEFAULT);
return true;
}
return false;
}
// 检查是否碰到星星
bool checkStarCollision() {
if (isWin || isFalling) return false;
// 星星的位置在最后一块地面上方
Land& lastLand = scene.land.back();
// 修正星星位置计算:使用中心点坐标
float starX = lastLand.x - scene.im_star.getwidth() / 2;
float starY = lastLand.top_y - scene.im_star.getheight() - 30;
float starWidth = scene.im_star.getwidth();
float starHeight = scene.im_star.getheight();
// 玩家位置
float playerLeft = x_left;
float playerRight = x_left + width;
float playerTop = y_bottom - height;
float playerBottom = y_bottom;
// 检测碰撞
if (playerRight > starX && playerLeft < starX + starWidth &&
playerBottom > starY && playerTop < starY + starHeight) {
isWin = true;
isFalling = true;
vy = 0; // 重置垂直速度
return true;
}
return false;
}
// 检查是否碰到盘子
bool checkPanCollision() {
if (!isFalling) return false;
Land& lastLand = scene.land.back();
// 盘子位置在星星正下方
float panX = lastLand.x - scene.panWidth / 2;
float panY = lastLand.top_y + 600; // 在星星下方600像素处
// 玩家位置
float playerLeft = x_left;
float playerRight = x_left + width;
float playerBottom = y_bottom;
// 检测碰撞(扩大碰撞范围)
if (playerBottom >= panY - 30 && playerBottom <= panY + 30 &&
playerRight > panX && playerLeft < panX + scene.panWidth) {
// 碰到盘子,停止自由落体
isFalling = false;
// 调整玩家位置到盘子上方
y_bottom = panY;
PlaySoundA("music/victory.wav", NULL, SND_FILENAME | SND_ASYNC | SND_NODEFAULT);
return true;
}
return false;
}
};
Player player;
bool gameOver = false;
bool gameWin = false;
void startup() {
srand(time(0));
scene.initialize();
player.initialize();
initgraph(WIDTH, HEIGHT, SHOWCONSOLE);
BeginBatchDraw();
gameStartTime = clock(); // 记录游戏开始时间
}
void show() {
if (gameOver) return;
cleardevice();
scene.draw(player.x_left - WIDTH / 2, player.y_bottom - HEIGHT / 2);
player.draw();
TCHAR buffer[100];
wsprintf(buffer, _T("分数: %d | 生命: %d"), player.score, player.lives);
setbkmode(TRANSPARENT);
settextcolor(RED);
settextstyle(20, 0, _T("宋体"));
outtextxy(10, 10, buffer);
FlushBatchDraw();
Sleep(30);
}
void withinput() {
player.standstill();
if (gameOver) return;
player.standstill();
if (_kbhit()) {
if (GetAsyncKeyState(VK_RIGHT) || GetAsyncKeyState('D'))
player.walkRight(scene);
else if (GetAsyncKeyState(VK_LEFT) || GetAsyncKeyState('A'))
player.walkLeft(scene);
if (GetAsyncKeyState(VK_UP) || GetAsyncKeyState('W'))
player.beginjump();
}
}
void withoutinput() {
if (gameOver) return;
// 检查是否碰到星星
if (player.checkStarCollision()) {
// 玩家碰到星星后,调整位置确保在屏幕中央
player.x_left = scene.land.back().x - player.width/2;
}
// 如果是自由落体状态
if (player.isFalling) {
// 应用自由落体物理
player.vy += player.fallingG;
player.y_bottom += player.vy;
// 检查是否碰到盘子
if (player.checkPanCollision()) {
gameWin = true;
// 停止背景音乐
stopBackgroundMusic();
PlaySoundA("music/victory.wav", NULL, SND_FILENAME | SND_ASYNC | SND_NODEFAULT);
return;
}
}
else {
player.updateKeycode(scene);
// 更新敌人位置
for (int i = 0; i < scene.enemies.size(); i++) {
scene.enemies[i].update(scene.land);
}
// 检查玩家与敌人碰撞
for (int i = 0; i < scene.enemies.size(); i++) {
if (player.stompEnemy(scene.enemies[i])) {
// 踩踏成功处理
}
else {
// 检查其他碰撞
float playerRight = player.x_left + player.width;
float playerBottom = player.y_bottom;
float enemyLeft = scene.enemies[i].x - scene.enemies[i].e_width / 2;
float enemyRight = scene.enemies[i].x + scene.enemies[i].e_width / 2;
float enemyTop = scene.enemies[i].y - scene.enemies[i].e_height / 2;
float enemyBottom = scene.enemies[i].y + scene.enemies[i].e_height / 2;
if (player.x_left < enemyRight &&
playerRight > enemyLeft &&
player.y_bottom > enemyTop &&
playerBottom < enemyBottom &&
scene.enemies[i].isAlive) {
player.lives--;
// 播放生命值减少音效
PlaySoundA("music/lostblood.wav", NULL, SND_FILENAME | SND_ASYNC | SND_NODEFAULT);
if (player.lives <= 0) {
// 停止背景音乐
stopBackgroundMusic();
// 播放游戏结束音效
PlaySoundA("music/defeat.wav", NULL, SND_FILENAME | SND_ASYNC | SND_NODEFAULT);
gameOver = true;
scene.showGameOver();
return;
}
// 显示剩余生命值
scene.showLifeInfo(player.lives);
// 重置玩家位置
if (!scene.land.empty()) {
player.x_left = scene.land[0].x - player.width / 2;
player.y_bottom = scene.land[0].top_y;
}
else {
player.x_left = WIDTH / 2;
player.y_bottom = HEIGHT - 100;
}
player.vy = 0;
// 重置敌人
for (auto& enemy : scene.enemies) {
enemy.isAlive = true;
}
return;
}
}
}
// 检查道具碰撞
for (int i = 0; i < scene.moneys.size(); i++) {
if (scene.moneys[i].checkCollision(player.x_left, player.y_bottom, player.width, player.height)) {
player.score += 10;
// 播放收集金钱音效
PlaySoundA("music/moneymusic.wav", NULL, SND_FILENAME | SND_ASYNC | SND_NODEFAULT);
scene.moneys.erase(scene.moneys.begin() + i);
i--;
}
}
// 检查掉落
if (player.y_bottom > HEIGHT * 1.5) {
player.lives--;
// 播放生命值减少音效
PlaySoundA("music/lostblood.wav", NULL, SND_FILENAME | SND_ASYNC | SND_NODEFAULT);
if (player.lives <= 0) {
// 停止背景音乐
stopBackgroundMusic();
// 播放游戏结束音效
PlaySoundA("music/defeat.wav", NULL, SND_FILENAME | SND_ASYNC | SND_NODEFAULT);
gameOver = true;
scene.showGameOver();
return;
}
// 显示剩余生命值
scene.showLifeInfo(player.lives);
// 重置玩家位置
if (!scene.land.empty()) {
player.x_left = scene.land[0].x - player.width / 2;
player.y_bottom = scene.land[0].top_y;
}
else {
player.x_left = WIDTH / 2;
player.y_bottom = HEIGHT - 100;
}
player.vy = 0;
}
}
};
int main() {
startup();
mp3Thread = new std::thread(playMP3, "music/bkmusic.mp3");
while (true) {
show();
withinput();
withoutinput();
if (gameOver) {
// 这里不再需要播放defeat音效,因为已经在withoutinput中播放过了
break;
}
if (gameWin) {
double timeTaken = (double)(clock() - gameStartTime) / CLOCKS_PER_SEC;
// 显示胜利结算画面
scene.showVictoryScreen(player.score,timeTaken);
break;
}
}
// 游戏结束后关闭图形窗口
_getch();
closegraph();
if (mp3Thread && mp3Thread->joinable()) {
stopPlayback.store(true);
mp3Thread->join();
}
delete mp3Thread;
return 0;
}
最新发布