From ffd15071f0b54484378769b4ba05c05403358590 Mon Sep 17 00:00:00 2001 From: ayhnencac <3482579672@qq.com> Date: Thu, 9 Jan 2025 23:28:02 +0800 Subject: [PATCH] happy --- src/battle_game/core/units/snaky_tank.cpp | 219 ++++++++++++++++++++++ src/battle_game/core/units/snaky_tank.h | 30 +++ 2 files changed, 249 insertions(+) create mode 100644 src/battle_game/core/units/snaky_tank.cpp create mode 100644 src/battle_game/core/units/snaky_tank.h diff --git a/src/battle_game/core/units/snaky_tank.cpp b/src/battle_game/core/units/snaky_tank.cpp new file mode 100644 index 00000000..e3bf1583 --- /dev/null +++ b/src/battle_game/core/units/snaky_tank.cpp @@ -0,0 +1,219 @@ +#include "battle_game/core/bullets/bullets.h" +#include "battle_game/core/game_core.h" +#include "battle_game/graphics/graphics.h" +#include "snaky_tank.h" +namespace battle_game { + +void DrawCircle(const glm::vec2 &position, + float radius) { + // 设置颜色 + SetColor(glm::vec4{1.0f}); + + // 设置变换矩阵 + SetTransformation(position, 0.0f); + + // 绘制圆形 + const int segments = 100; + std::vector vertices; + for (int i = 0; i < segments; ++i) { + float theta = 2.0f * glm::pi() * float(i) / float(segments); + float x = radius * cosf(theta); + float y = radius * sinf(theta); + vertices.emplace_back(x, y); + } + + // 绘制线条 + for (int i = 0; i < segments; ++i) { + int next = (i + 1) % segments; + //DrawLine(vertices[i], vertices[next]); + } +} + +} // namespace battle_game + +namespace battle_game::unit { + +namespace { +uint32_t tank_body_model_index = 0xffffffffu; +uint32_t tank_turret_model_index = 0xffffffffu; +} // namespace + +Snaky::Snaky(GameCore *game_core, uint32_t id, uint32_t player_id) + : Unit(game_core, id, player_id) { + if (!~tank_body_model_index) { + auto mgr = AssetsManager::GetInstance(); + { + /* Tank Body */ + tank_body_model_index = mgr->RegisterModel( + { + {{-0.8f, 0.8f}, {0.0f, 0.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, + {{-0.8f, -1.0f}, {0.0f, 0.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, + {{0.8f, 0.8f}, {0.0f, 0.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, + {{0.8f, -1.0f}, {0.0f, 0.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, + // distinguish front and back + {{0.6f, 1.0f}, {0.0f, 0.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, + {{-0.6f, 1.0f}, {0.0f, 0.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, + }, + {0, 1, 2, 1, 2, 3, 0, 2, 5, 2, 4, 5}); + } + + { + /* Tank Turret */ + std::vector turret_vertices; + std::vector turret_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() * 2.0f; + auto sin_theta = std::sin(theta); + auto cos_theta = std::cos(theta); + turret_vertices.push_back({{sin_theta * 0.5f, cos_theta * 0.5f}, + {0.0f, 0.0f}, + {0.7f, 0.7f, 0.7f, 1.0f}}); + turret_indices.push_back(i); + turret_indices.push_back((i + 1) % precision); + turret_indices.push_back(precision); + } + turret_vertices.push_back( + {{0.0f, 0.0f}, {0.0f, 0.0f}, {0.7f, 0.7f, 0.7f, 1.0f}}); + turret_vertices.push_back( + {{-0.1f, 0.0f}, {0.0f, 0.0f}, {0.7f, 0.7f, 0.7f, 1.0f}}); + turret_vertices.push_back( + {{0.1f, 0.0f}, {0.0f, 0.0f}, {0.7f, 0.7f, 0.7f, 1.0f}}); + turret_vertices.push_back( + {{-0.1f, 1.2f}, {0.0f, 0.0f}, {0.7f, 0.7f, 0.7f, 1.0f}}); + turret_vertices.push_back( + {{0.1f, 1.2f}, {0.0f, 0.0f}, {0.7f, 0.7f, 0.7f, 1.0f}}); + turret_indices.push_back(precision + 1 + 0); + turret_indices.push_back(precision + 1 + 1); + turret_indices.push_back(precision + 1 + 2); + turret_indices.push_back(precision + 1 + 1); + turret_indices.push_back(precision + 1 + 2); + turret_indices.push_back(precision + 1 + 3); + tank_turret_model_index = + mgr->RegisterModel(turret_vertices, turret_indices); + } + } +} + +void Snaky::Render() { + battle_game::SetTransformation(position_, rotation_); + battle_game::SetTexture(0); + battle_game::SetColor(game_core_->GetPlayerColor(player_id_)); + battle_game::DrawModel(tank_body_model_index); + battle_game::SetRotation(turret_rotation_); + battle_game::DrawModel(tank_turret_model_index); + if (shield_active_) { + // Render shield effect + battle_game::SetColor({0.0f, 0.5f, 1.0f, 0.5f}); + battle_game::DrawCircle(position_, 1.5f); + } +} +void Snaky::UpdateShield() { + if (shield_duration_ > 0) { + shield_duration_--; + if (shield_duration_ == 0) { + shield_active_ = false; + } + } +} +void Snaky::ActivateShield(uint32_t duration) { + auto player = game_core_->GetPlayer(player_id_); + auto &input_data = player->GetInputData(); + if (input_data.key_down[GLFW_KEY_G]) { + shield_active_ = true; + shield_duration_ = duration; + } +} + +void Snaky::Update() { + TankMove(3.0f, glm::radians(180.0f)); + TurretRotate(); + Fire(); + UpdateShield(); + ActivateShield(2); // Shield duration 2 seconds. +} + +void Snaky::TankMove(float move_speed, float rotate_angular_speed) { + auto player = game_core_->GetPlayer(player_id_); + if (player) { + auto &input_data = player->GetInputData(); + glm::vec2 offset{0.0f}; + if (input_data.key_down[GLFW_KEY_W]) { + offset.y += 1.0f; + } + if (input_data.key_down[GLFW_KEY_S]) { + offset.y -= 1.0f; + } + 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 = 0.0f; + if (input_data.key_down[GLFW_KEY_A]) { + rotation_offset += 1.0f; + } + if (input_data.key_down[GLFW_KEY_D]) { + rotation_offset -= 1.0f; + } + rotation_offset *= kSecondPerTick * rotate_angular_speed * GetSpeedScale(); + game_core_->PushEventRotateUnit(id_, rotation_ + rotation_offset); + } +} + +void Snaky::TurretRotate() { + auto player = game_core_->GetPlayer(player_id_); + if (player) { + auto &input_data = player->GetInputData(); + auto diff = input_data.mouse_cursor_position - position_; + if (glm::length(diff) < 1e-4) { + turret_rotation_ = rotation_; + } else { + turret_rotation_ = std::atan2(diff.y, diff.x) - glm::radians(90.0f); + } + } +} + +void Snaky::Fire() { + if (fire_count_down_ == 0) { + auto player = game_core_->GetPlayer(player_id_); + if (player) { + auto &input_data = player->GetInputData(); + if (input_data.mouse_button_down[GLFW_MOUSE_BUTTON_LEFT]) { + auto velocity = Rotate(glm::vec2{0.0f, 20.0f}, turret_rotation_); + GenerateBullet( + position_ + Rotate({0.0f, 1.2f}, turret_rotation_), + turret_rotation_, GetDamageScale(), velocity); + fire_count_down_ = kTickPerSecond; // Fire interval 1 second. + } + } + } + if (fire_count_down_) { + fire_count_down_--; + } +} + +bool Snaky::IsHit(glm::vec2 position) const { + if (shield_active_) { + return false; // Shield is active, no hit detected + } + position = WorldToLocal(position); + return position.x > -0.8f && position.x < 0.8f && position.y > -1.0f && + position.y < 1.0f && position.x + position.y < 1.6f && + position.y - position.x < 1.6f; +} + +const char *Snaky::UnitName() const { + return "Snaky"; +} + +const char *Snaky::Author() const { + return "ayhnencac"; +} +} // namespace battle_game::unit diff --git a/src/battle_game/core/units/snaky_tank.h b/src/battle_game/core/units/snaky_tank.h new file mode 100644 index 00000000..efe90e36 --- /dev/null +++ b/src/battle_game/core/units/snaky_tank.h @@ -0,0 +1,30 @@ +#pragma once +#include "battle_game/core/unit.h" + +namespace battle_game::unit { +class Snaky : public Unit { + public: + Snaky(GameCore *game_core, uint32_t id, uint32_t player_id); + void Render() override; + void Update() override; + void UpdateShield(); + void ActivateShield(uint32_t duration); + [[nodiscard]] bool IsHit(glm::vec2 position) const override; + + protected: + void TankMove(float move_speed, float rotate_angular_speed); + void TurretRotate(); + + void Fire(); + [[nodiscard]] const char *UnitName() const override; + [[nodiscard]] const char *Author() const override; + + float turret_rotation_{0.0f}; + uint32_t fire_count_down_{0}; + uint32_t mine_count_down_{0}; + + private: + bool shield_active_{false}; + uint32_t shield_duration_{0}; +}; +} // namespace battle_game::unit