Skip to content

Commit

Permalink
Gold(In fact, Brown) Hopper: A Special Enemy
Browse files Browse the repository at this point in the history
  • Loading branch information
myeeye committed Jan 8, 2025
1 parent 11807ae commit b251ca0
Show file tree
Hide file tree
Showing 14 changed files with 264 additions and 7 deletions.
Binary file added assets/textures/killerball.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/battle_game/app/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,9 @@ void App::CaptureInput() {
void App::SetScene() {
my_player_id_ = game_core_->AddPlayer();
auto enemy_player_id = game_core_->AddPlayer();
game_core_->GetPlayer(enemy_player_id)->SelectedUnit() = 1;
goldhopper_id = game_core_->AddPlayer();
game_core_->GetPlayer(goldhopper_id)->SelectedUnit() = 2;
game_core_->SetRenderPerspective(my_player_id_);
}

Expand Down
2 changes: 1 addition & 1 deletion src/battle_game/app/app.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class App {

std::unique_ptr<vulkan_legacy::framework::RenderNode> render_node_;

uint32_t my_player_id_{0};
uint32_t my_player_id_{0}, goldhopper_id{0};
float fov_y_{10.0f};
};
} // namespace battle_game
1 change: 1 addition & 0 deletions src/battle_game/core/bullets/bullets.h
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
#pragma once
#include "battle_game/core/bullets/cannon_ball.h"
#include "battle_game/core/bullets/killer_ball.h"
2 changes: 1 addition & 1 deletion src/battle_game/core/bullets/cannon_ball.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ void CannonBall::Update() {
continue;
}
if (unit.second->IsHit(position_)) {
game_core_->PushEventDealDamage(unit.first, id_, damage_scale_ * 10.0f);
game_core_->PushEventDealDamage2(unit.first, id_, unit_id_, damage_scale_ * 10.0f);
should_die = true;
}
}
Expand Down
50 changes: 50 additions & 0 deletions src/battle_game/core/bullets/killer_ball.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#include "battle_game/core/bullets/killer_ball.h"

#include "battle_game/core/game_core.h"
#include "battle_game/core/particles/particles.h"

namespace battle_game::bullet {
KillerBall::KillerBall(GameCore *core,
uint32_t id,
uint32_t unit_id,
uint32_t player_id,
glm::vec2 position,
float rotation,
float damage_scale)
: Bullet(core, id, unit_id, player_id, position, rotation, damage_scale),
death_count_down_(kTickPerSecond*game_core_->RandomInt(5,20)) {
}

void KillerBall::Render() {
SetTransformation(position_, rotation_, glm::vec2{0.1f});
SetColor(game_core_->GetPlayerColor(player_id_));
SetTexture(BATTLE_GAME_ASSETS_DIR "textures/killerball.png");
DrawModel(0);
}

void KillerBall::Update() {
if (!death_count_down_) {
game_core_->PushEventRemoveBullet(id_);
return;
}
death_count_down_--;

auto &units = game_core_->GetUnits();
for (auto &unit : units) {
if (unit.first == unit_id_) {
continue;
}
if (unit.second->IsHit(position_)) {
game_core_->PushEventDealDamage2(unit.first, id_, unit_id_, damage_scale_ * game_core_->RandomFloat() / 2);
}
}
}

KillerBall::~KillerBall() {
for (int i = 0; i < 5; i++) {
game_core_->PushEventGenerateParticle<particle::Smoke>(
position_, rotation_, game_core_->RandomInCircle() * 2.0f, 0.2f,
glm::vec4{0.0f, 0.0f, 0.0f, 1.0f}, 3.0f);
}
}
} // namespace battle_game::bullet
21 changes: 21 additions & 0 deletions src/battle_game/core/bullets/killer_ball.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once
#include "battle_game/core/bullet.h"

namespace battle_game::bullet {
class KillerBall : public Bullet {
public:
KillerBall(GameCore *core,
uint32_t id,
uint32_t unit_id,
uint32_t player_id,
glm::vec2 position,
float rotation,
float damage_scale);
~KillerBall() override;
void Render() override;
void Update() override;

private:
int death_count_down_;
};
} // namespace battle_game::bullet
26 changes: 26 additions & 0 deletions src/battle_game/core/game_core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,21 @@ void GameCore::PushEventDealDamage(uint32_t dst_unit_id,
});
}

void GameCore::PushEventDealDamage2(uint32_t dst_unit_id,
uint32_t src_unit_id,
uint32_t killer_id,
float damage) {
event_queue_.emplace([=]() {
auto unit = GetUnit(dst_unit_id);
if (unit) {
unit->SetHealth(unit->GetHealth() - damage / unit->GetMaxHealth());
if (unit->GetHealth() <= 0.0f) {
PushEventKillUnit2(dst_unit_id, src_unit_id, killer_id);
}
}
});
}

void GameCore::PushEventRemoveObstacle(uint32_t obstacle_id) {
event_queue_.emplace([=]() {
if (obstacles_.count(obstacle_id)) {
Expand Down Expand Up @@ -265,6 +280,14 @@ void GameCore::PushEventKillUnit(uint32_t dst_unit_id, uint32_t src_unit_id) {
event_queue_.emplace([=]() { PushEventRemoveUnit(dst_unit_id); });
}

void GameCore::PushEventKillUnit2(uint32_t dst_unit_id, uint32_t src_unit_id, uint32_t killer_id) {
event_queue_.emplace([=]() {
auto x=GetUnit(dst_unit_id),y=GetUnit(killer_id);
if(x&&y&&x->GetPlayerId()==3&&y->GetPlayerId()!=3) y->SetHealth(y->GetHealth()*2);
PushEventRemoveUnit(dst_unit_id);
});
}

float GameCore::RandomFloat() {
return std::uniform_real_distribution<float>()(random_device_);
}
Expand All @@ -276,8 +299,11 @@ int GameCore::RandomInt(int low_bound, int high_bound) {

void GameCore::SetScene() {
AddObstacle<obstacle::Block>(glm::vec2{-3.0f, 4.0f});
respawn_points_.emplace_back(glm::vec2{-5.0f, -5.0f}, glm::radians(45.0f));
respawn_points_.emplace_back(glm::vec2{-7.0f, -7.0f}, glm::radians(45.0f));
respawn_points_.emplace_back(glm::vec2{0.0f}, 0.0f);
respawn_points_.emplace_back(glm::vec2{3.0f, 4.0f}, glm::radians(90.0f));
respawn_points_.emplace_back(glm::vec2{3.0f, -4.0f}, glm::radians(90.0f));
boundary_low_ = {-10.0f, -10.0f};
boundary_high_ = {10.0f, 10.0f};
}
Expand Down
2 changes: 2 additions & 0 deletions src/battle_game/core/game_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ class GameCore {
void PushEventDealDamage(uint32_t dst_unit_id,
uint32_t src_unit_id,
float damage);
void PushEventDealDamage2(uint32_t dst_unit_id, uint32_t src_unit_id, uint32_t killer_id, float damage);
void PushEventKillUnit(uint32_t dst_unit_id, uint32_t src_unit_id);
void PushEventKillUnit2(uint32_t dst_unit_id, uint32_t src_unit_id, uint32_t killer_id);
void PushEventRemoveObstacle(uint32_t obstacle_id);
void PushEventRemoveBullet(uint32_t bullet_id);
void PushEventRemoveParticle(uint32_t particle_id);
Expand Down
2 changes: 2 additions & 0 deletions src/battle_game/core/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ void Player::Update() {
if (!primary_unit) {
if (!resurrection_count_down_) {
resurrection_count_down_ = kTickPerSecond * 5; // Respawn after 5 seconds
if (id_ == 3)
resurrection_count_down_ = kTickPerSecond * game_core_->RandomInt(20,60);
}
resurrection_count_down_--;
if (!resurrection_count_down_) {
Expand Down
2 changes: 2 additions & 0 deletions src/battle_game/core/selectable_units.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ void GameCore::GeneratePrimaryUnitList() {
* */
ADD_SELECTABLE_UNIT(unit::Tank);
ADD_SELECTABLE_UNIT(unit::MyeeTank);
// ADD_SELECTABLE_UNIT(unit::GoldHopper);
AddPrimaryUnitAllocationFunction<unit::GoldHopper>();

unit.reset();
}
Expand Down
125 changes: 125 additions & 0 deletions src/battle_game/core/units/goldhopper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#include "goldhopper.h"

#include "battle_game/core/bullets/bullets.h"
#include "battle_game/core/game_core.h"
#include "battle_game/graphics/graphics.h"

namespace battle_game::unit {

namespace {
uint32_t hopper_model_index = 0xffffffffu;
} // namespace

GoldHopper::GoldHopper(GameCore *game_core, uint32_t id, uint32_t player_id)
: Unit(game_core, id, player_id) {
if (!~hopper_model_index) {
auto mgr = AssetsManager::GetInstance();
std::vector<ObjectVertex> vertices;
std::vector<uint32_t> indices;
const int precision = 60;
const float inv_precision = 1.0f / float(precision);
for (int i = 0; i < precision; i++) {
auto theta = (float(i) + 0.5f) * inv_precision;
theta *= glm::pi<float>() * 2.0f;
auto sin_theta = std::sin(theta);
auto cos_theta = std::cos(theta);
vertices.push_back({{sin_theta * 0.5f, cos_theta * 0.5f},
{0.0f, 0.0f},
{0.5f, 0.5f, 0.0f, 1.0f}});
indices.push_back(i);
indices.push_back((i + 1) % precision);
indices.push_back(precision);
}
vertices.push_back({{0.0f, 0.0f}, {0.0f, 0.0f}, {0.5f, 0.5f, 0.0f, 1.0f}});
vertices.push_back({{0.1f, 0.0f}, {0.0f, 0.0f}, {0.5f, 0.5f, 0.0f, 1.0f}});
vertices.push_back({{-0.1f, 0.0f}, {0.0f, 0.0f}, {0.5f, 0.5f, 0.0f, 1.0f}});
vertices.push_back({{0.0f, 0.7f}, {0.0f, 0.0f}, {0.5f, 0.5f, 0.0f, 1.0f}});
indices.push_back(precision+1);
indices.push_back(precision+2);
indices.push_back(precision+3);
hopper_model_index = mgr->RegisterModel(vertices, indices);
}
OldHealth=GetHealth();
}

void GoldHopper::Render() {
battle_game::SetTransformation(position_, rotation_);
battle_game::SetTexture(0);
battle_game::SetColor({1,0.5,0,1});
battle_game::DrawModel(hopper_model_index);
}

void GoldHopper::RandomRun()
{
if(!move_count_down_)return;
float move_speed = (float) move_count_down_ / kTickPerSecond;
float rotate_angular_speed = glm::radians(180.0f) * ((float)move_count_down_ / kTickPerSecond / 2);
move_count_down_--;
auto player = game_core_->GetPlayer(player_id_);
if (player) {
glm::vec2 offset{game_core_->RandomFloat()/2+0.5f};
float speed = move_speed * GetSpeedScale();
offset *= kSecondPerTick * speed;
auto new_position =
position_ + glm::vec2{glm::rotate(glm::mat4{1.0f}, rotation_,
glm::vec3{0.0f, 0.0f, 1.0f}) *
glm::vec4{offset, 0.0f, 0.0f}};
if (!game_core_->IsBlockedByObstacles(new_position)) {
game_core_->PushEventMoveUnit(id_, new_position);
}
float rotation_offset = std::clamp(game_core_->RandomFloat()*3.0f-1.5f,-1.0f,1.0f);
rotation_offset *= kSecondPerTick * rotate_angular_speed * GetSpeedScale();
game_core_->PushEventRotateUnit(id_, rotation_ + rotation_offset);
}
}

void GoldHopper::Bang()
{
if(!bang_count_down_)return;
bang_count_down_--;
if(health_>=0.4)return;
float t = 0.4 / health_ * bang_count_down_ / kTickPerSecond / 10000;
if(game_core_->RandomFloat() < t)
{
game_core_->PushEventDealDamage(id_,id_,2*GetMaxHealth());
GenerateBullet<bullet::KillerBall>(position_, 0, GetDamageScale());
}
}

void GoldHopper::Update()
{
if(OldHealth>GetHealth()+0.0001)
{
uint32_t c=20*kTickPerSecond*(OldHealth-GetHealth());
bang_count_down_+=c,move_count_down_+=c;
}
OldHealth=GetHealth();
RandomRun();
Bang();
}

bool GoldHopper::IsHit(glm::vec2 position) const {
position = WorldToLocal(position);
return position.x*position.x+position.y*position.y<0.25||(position.y>0&&7*fabs(position.x)+position.y<0.7);
}

float GoldHopper::GetDamageScale() const {
return 3.0f;
}

float GoldHopper::GetSpeedScale() const {
return 3.5f;
}

float GoldHopper::BasicMaxHealth() const {
return 25.0f;
}

const char *GoldHopper::UnitName() const {
return "GoldHopper";
}

const char *GoldHopper::Author() const {
return "MyeeYe";
}
} // namespace battle_game::unit
24 changes: 24 additions & 0 deletions src/battle_game/core/units/goldhopper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once
#include "battle_game/core/unit.h"

namespace battle_game::unit {
class GoldHopper : public Unit {
public:
GoldHopper(GameCore *game_core, uint32_t id, uint32_t player_id);
void Render() override;
void Update() override;
[[nodiscard]] bool IsHit(glm::vec2 position) const override;

protected:
void RandomRun();
void Bang();
[[nodiscard]] float GetDamageScale() const override;
[[nodiscard]] float GetSpeedScale() const override;
[[nodiscard]] float BasicMaxHealth() const override;
[[nodiscard]] const char *UnitName() const override;
[[nodiscard]] const char *Author() const override;
uint32_t move_count_down_{0};
uint32_t bang_count_down_{0};
float OldHealth{0};
};
} // namespace battle_game::unit
11 changes: 6 additions & 5 deletions src/battle_game/core/units/myee_tank.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ void MyeeTank::Fire() {
GenerateBullet<bullet::CannonBall>(
position_ + Rotate({0.0f, 1.2f}, turret_rotation_),
turret_rotation_, GetDamageScale(), velocity);
fire_count_down_ = kTickPerSecond; // Fire interval 1 second.
fire_count_down_ = kTickPerSecond / 2; // Fire interval 0.5 second.
}
}
}
Expand All @@ -152,19 +152,20 @@ bool MyeeTank::IsHit(glm::vec2 position) const {
const glm::vec2 X[6]={{-1.0f, 0.1f},{-0.1f, 1.0f},{0.1f, 1.0f},{1.0f, 0.1f},{0.8f, -1.0f},{-0.8f, -1.0f}};
auto cross=[](glm::vec2 a,glm::vec2 b){return a.x*b.y-a.y*b.x<0;};
bool ok = true;
for(int j=0;ok&&j<6;j++)ok=cross(position-X[j],X[(j+1)%6]-X[j]);
for(int j=0;ok&&j<6;j++)ok=cross(X[(j+1)%6]-X[j],position-X[j]);
return ok;
}

float MyeeTank::GetDamageScale() const {
return 1.2f;
return 0.8f;
}

float MyeeTank::GetSpeedScale() const {
return 1.2f;
return 1.5f;
}

float MyeeTank::BasicMaxHealth() const {
return 40.0f;
return 50.0f;
}

const char *MyeeTank::UnitName() const {
Expand Down

0 comments on commit b251ca0

Please sign in to comment.