植物明星大乱斗血包道具制作,简单的bullet类延展设计
菜鸟的游戏学习实践记录O.O
先来看看血包的游戏内展示
其中那个红色的小球,就是血包,吃了之后可以加30hp。
具体思路及代码设计
1.私有属性与接口设计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| \\ hp_ball.h
class HpBall { public: HpBall() = default; ~HpBall() = default;
void on_draw(const Camera& camera); void on_update(int delta); bool check_if_exceeds_screen(); void on_collision(Player*& player); bool check_collision(Player*& player); bool check_can_remove() const;
private: Vector2 position; Vector2 size; Vector2 velocity;
int add_hp = 30; bool can_remove = false; PlayerID target_id = PlayerID::P1; Timer timer_hp_ball_remove; };
|
由于我们需要知道与血包碰撞的角色ID,同时还要对该角色的hp进行修改操作,所以不得不来到player类中增加接口:
1 2 3 4 5
|
public: void add_hp(int add) { hp = min(100, hp + add); } PlayerID& get_playerID() { return id; }
|
2.血包的生命周期管理
hp_ball类与bullet类十分相似,因此我们可以仿照bullet的生命周期,设计一个全局vector:
1 2 3
|
std::vector<HpBall*> hp_ball_list;
|
但是,与bullet类不同的是,hp_ball类的生成并不归player管,而应该由更上层的模块进行管理,为避免过多的全局变量,生成与删除hp_ball的工作我们都交给game_scene:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
|
private: Timer timer_create_hp_ball; bool can_hp_ball_create = true;
public: timer_create_hp_ball.set_wait_time(4000); timer_create_hp_ball.set_one_shot(false); timer_create_hp_ball.set_callback([&]() { can_hp_ball_create = true; });
timer_create_hp_ball.on_update(delta); if (can_hp_ball_create) { HpBall* hp_ball = new HpBall(); hp_ball_list.push_back(hp_ball); can_hp_ball_create = false; }
hp_ball_list.erase(std::remove_if( hp_ball_list.begin(), hp_ball_list.end(), [](const HpBall* hp_ball) { bool deletable = hp_ball->check_can_remove(); if (deletable) delete hp_ball; return deletable; }), hp_ball_list.end());
for (HpBall* hp_ball : hp_ball_list) hp_ball->on_update(delta);
for (HpBall* hp_ball : hp_ball_list) hp_ball->on_draw(camera);
|
3.随机生成血包位置
众所那个周知,使用
1 2
| srand((int)time(0)); rand();
|
就可以生成每次都不一样的随机数,但如果粗暴地将这一套放入循环内,或HpBall的构造函数中,就会惊讶地发现,每次小球生成的位置居然是一样的,虽然每次运行后小球的位置会有所改变,但小球在整局游戏中,都只会在这个位置生成了,非常boring。(原理应该是随机数种子在生成时被固定了?我太菜了还没有完全搞懂sos)
总之,解决方法是这样的:
然后就可以在HpBall中使用构造函数随机生成x轴位置了,每次实例化HpBall都会拥有一个随机的x坐标
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
HpBall() { size.x = 70, size.y = 70; position.x = rand() % getwidth(); position.y = 35; velocity.y = 0.3f, velocity.x = 0;
timer_hp_ball_remove.set_wait_time(5000); timer_hp_ball_remove.set_one_shot(true); timer_hp_ball_remove.set_callback([&]() { can_remove = true; }); }
|
完整的HpBall代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
|
#ifndef _HP_BALL_H_ #define _HP_BALL_H_
#include "easyx.h" #include "vector2.h" #include "player_id.h" #include "player.h"
#include <time.h> #include <stdlib.h> #include <functional> #include <vector>
extern Player* player_1; extern Player* player_2;
class HpBall { public: HpBall() { size.x = 70, size.y = 70; position.x = rand() % getwidth(); position.y = 35; velocity.y = 0.3f, velocity.x = 0;
timer_hp_ball_remove.set_wait_time(5000); timer_hp_ball_remove.set_one_shot(true); timer_hp_ball_remove.set_callback([&]() { can_remove = true; }); }
~HpBall() = default;
void on_draw(const Camera& camera) { setlinecolor(RGB(255, 155, 50)); setfillcolor(RGB(200, 75, 10)); fillcircle(position.x, position.y, 35); }
void on_update(int delta) { position += velocity * (float)delta;
if (check_if_exceeds_screen()) can_remove = true;
timer_hp_ball_remove.on_update(delta);
on_collision(player_1); on_collision(player_2); }
bool check_if_exceeds_screen() { return (position.x + size.x <= 0 || position.x >= getwidth() || position.y + size.y <= 0 || position.y >= getheight()); }
void on_collision(Player*& player) { if (check_collision(player)) { target_id = player->get_playerID(); if (target_id == PlayerID::P1) player_1->add_hp(add_hp); else player_2->add_hp(add_hp); can_remove = true; } }
bool check_collision(Player*& player) { return this->position.x + this->size.x / 2 >= player->get_position().x && this->position.x + this->size.x / 2 <= player->get_position().x + player->get_size().x && this->position.y + this->size.y / 2 >= player->get_position().y && this->position.y + this->size.y / 2 <= player->get_position().y + player->get_size().y; }
bool check_can_remove() const { return can_remove; }
private: Vector2 position; Vector2 size; Vector2 velocity;
int add_hp = 30; bool can_remove = false; PlayerID target_id = PlayerID::P1; Timer timer_hp_ball_remove; };
#endif
|
除了hp_ball.h外,game_scene与main、player类都有改动,以及相互extern的操作,所以以上并非全部的实现代码。
碎碎念
其实HpBall应该完全可以通过继承Bullet类来实现,修改一下Bullet类便可以更完美地实现解耦,日后我也会继续进行改进。
其实我是一名经济学大二的学生哈哈哈哈哈,但制作游戏真的太好玩了,也十分谢谢大V老师启发并满足了我学习的欲望,这也是我第一篇学习记录,希望可以成为一个美好的开端吧。
Best Wishes To Everyone
最新消息
大V老师直播做了个我的高级版,私密马赛,发晚了:no_mouth: