功能实现

  1. 游戏加载场景
  2. 精灵动画
  3. 基本的角色UI

游戏加载场景

上一篇中我们说到游戏素材有点多,加载起来需要一定时间,所以我们这次专门创建一个线程用来进行游戏的加载

设定初始场景

Game::Game() {
    //
    gameSceneState = SCENE_LOADING;                    //初始默认游戏场景
    initMusic();                                    //初始化音乐
}

音乐初始化

void Game::initMusic() {
    gameStartMusic.setLoop(true);            ////背景音乐循环
    fightMusic.setLoop(true);
    gameStartMusic.play();
}

把加载素材的函数都写到一个里面

void Game::loadMediaData() {
    //
    loadCards();
    loadMusic();
    gameSceneState = SCENE_START;
}

加载场景的绘制

void Game::drawLoading() {
    Texture tBk, loads;
    stringstream ss;
    tBk.loadFromFile("data/bg/loading.png");
    Sprite sBk, sLoad;
    sBk.setTexture(tBk);
    sBk.setPosition(0, 0);
    window.draw(sBk);
    window.display();
}

主函数中

int main() {
    Game game;
    thread thLoad(&Game::loadMediaData, &game);            //创建一个线程加载游戏素材
    thLoad.detach();                                    //独立于主线程运行
    game.Run();
    return 0;
}

这样就会先加载游戏加载场景,等素材加载完后再进入游戏,免得素材比较多时造成窗口白屏以及无法操作的情况

加载动画

我们来完善一下加载界面,做一个加载的动画

像这样,准备一些用来做序列帧的图片

接下来我们定义一个Animation类,继承自Sprite

Animation.h

#pragma once
#include <SFML/Graphics.hpp>
using namespace sf;
class Animation :public Sprite {
public:

    Texture* frames;                    //纹理序列
    int frameLength;                    //序列量
    int frameNo = 0;                    //当前播放帧
    void bindFrames(Texture[], int);                //绑定序列
    void play();            //播放动画
};

Animation.cpp

#include "Animation.h"

void Animation::bindFrames(Texture tFrames[], int length) {        //传入纹理数组,数组长度
    frames = new Texture[length];                                //让内置的纹理数组等于
    for (int i = 0; i < length; i++) {                            //给动态定义长度
        frames[i] = tFrames[i];
    }
    frameLength = length;
}
void Animation::play() {
    setTexture(frames[frameNo]);            //设定当前帧的纹理
    frameNo += 1;                            //下一帧
    if (frameNo == frameLength) {            //重新开始播放
        frameNo = 0;
    }
}

初始化加载场景的数据

void Game::initLoading() {
    tLoadBk.loadFromFile("data/bg/loading.png");        //加载背景
    stringstream ss;
    for (int i = 0; i < 40; i++) {                        //加载动画序列
        ss << "data/anime/load" << i << ".png";
        tLoads[i].loadFromFile(ss.str());
        ss.str("");
    }
    sLoadBk.setTexture(tLoadBk);
    anLoading.bindFrames(tLoads, sizeof(tLoads) / sizeof(tLoads[0]));    //绑定动画序列
    anLoading.setScale(0.5, 0.5);                                        //缩放
}

绘制加载场景

void Game::drawLoading() {
    sLoadBk.setPosition(0, 0);
    window.draw(sLoadBk);
    anLoading.setPosition(800, 400);
    anLoading.play();                        //播放当前帧
    window.draw(anLoading);
    window.display();
}

最后在draw()函数中判断场景绘制即可

下面来看下效果

玩家,敌人的绘制

这里就比较简单了,就是单纯的绘制贴图

难点是hp条,mp条,行动力,卡池剩余牌数的改变,这些我们之后再做打算

为了还原真实的手牌,我们绘制手牌时对其设置偏移量,让其交叉绘制

void Game::drawCard() {
    for (int i = 0; i < humanPlayer.handCardNums; i++) {
        humanPlayer.handCards[i]->setPosition(300 + i * 150, 500);
        window.draw(*humanPlayer.handCards[i]);
    }
    window.display();                        //展示屏幕
}

以下是目前的效果

Last modification:February 12th, 2021 at 06:14 am