mirror of
				https://github.com/NoelFB/tiny_link.git
				synced 2025-11-04 02:21:33 +08:00 
			
		
		
		
	attack / hurt / bramble!!
This commit is contained in:
		@ -30,7 +30,7 @@ add_executable(game
 | 
			
		||||
	src/masks.h
 | 
			
		||||
	src/factory.h
 | 
			
		||||
	src/factory.cpp
 | 
			
		||||
 "src/assets/tileset.h" "src/assets/tileset.cpp" "src/components/tilemap.h" "src/components/tilemap.cpp")
 | 
			
		||||
 "src/assets/tileset.h" "src/assets/tileset.cpp" "src/components/tilemap.h" "src/components/tilemap.cpp" "src/components/hurtable.h" "src/components/hurtable.cpp" "src/components/timer.h" "src/components/timer.cpp")
 | 
			
		||||
 | 
			
		||||
# Reference blah
 | 
			
		||||
target_link_libraries(game blah)
 | 
			
		||||
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 168 B After Width: | Height: | Size: 187 B  | 
							
								
								
									
										
											BIN
										
									
								
								content/sprites/bramble.ase
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								content/sprites/bramble.ase
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								content/sprites/pop.ase
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								content/sprites/pop.ase
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							@ -14,6 +14,13 @@ const Sprite* Animator::sprite() const
 | 
			
		||||
	return m_sprite;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Sprite::Animation* Animator::animation() const
 | 
			
		||||
{
 | 
			
		||||
	if (m_sprite && m_animation_index >= 0 && m_animation_index < m_sprite->animations.size())
 | 
			
		||||
		return &m_sprite->animations[m_animation_index];
 | 
			
		||||
	return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Animator::play(const String& animation, bool restart)
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT(m_sprite, "No Sprite Assigned!");
 | 
			
		||||
 | 
			
		||||
@ -22,6 +22,8 @@ namespace TL
 | 
			
		||||
		Animator(const String& sprite);
 | 
			
		||||
 | 
			
		||||
		const Sprite* sprite() const;
 | 
			
		||||
		const Sprite::Animation* animation() const;
 | 
			
		||||
 | 
			
		||||
		void play(const String& animation, bool restart = false);
 | 
			
		||||
		void update() override;
 | 
			
		||||
		void render(Batch& batch) override;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										17
									
								
								src/components/hurtable.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/components/hurtable.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
			
		||||
#include "hurtable.h"
 | 
			
		||||
 | 
			
		||||
using namespace TL;
 | 
			
		||||
 | 
			
		||||
void Hurtable::update()
 | 
			
		||||
{
 | 
			
		||||
	if (collider && on_hurt && m_cooldown_timer <= 0)
 | 
			
		||||
	{
 | 
			
		||||
		if (collider->check(hurt_by))
 | 
			
		||||
		{
 | 
			
		||||
			m_cooldown_timer = cooldown;
 | 
			
		||||
			on_hurt(this);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m_cooldown_timer -= Time::delta;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								src/components/hurtable.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/components/hurtable.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "../world.h"
 | 
			
		||||
#include "collider.h"
 | 
			
		||||
#include <blah.h>
 | 
			
		||||
#include <functional>
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
namespace TL
 | 
			
		||||
{
 | 
			
		||||
	class Hurtable : public Component
 | 
			
		||||
	{
 | 
			
		||||
	private:
 | 
			
		||||
		float m_cooldown_timer = 0;
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		Collider* collider = nullptr;
 | 
			
		||||
		uint32_t hurt_by = 0;
 | 
			
		||||
		float cooldown = 1.0f;
 | 
			
		||||
		std::function<void(Hurtable* self)> on_hurt;
 | 
			
		||||
 | 
			
		||||
		void update() override;
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
@ -1,6 +1,8 @@
 | 
			
		||||
#include "player.h"
 | 
			
		||||
#include "mover.h"
 | 
			
		||||
#include "animator.h"
 | 
			
		||||
#include "collider.h"
 | 
			
		||||
#include "../masks.h"
 | 
			
		||||
 | 
			
		||||
using namespace TL;
 | 
			
		||||
 | 
			
		||||
@ -11,9 +13,12 @@ namespace
 | 
			
		||||
	constexpr float ground_accel = 500;
 | 
			
		||||
	constexpr float air_accel = 20;
 | 
			
		||||
	constexpr float friction = 800;
 | 
			
		||||
	constexpr float hurt_friction = 200;
 | 
			
		||||
	constexpr float gravity = 450;
 | 
			
		||||
	constexpr float jump_force = -105;
 | 
			
		||||
	constexpr float jump_time = 0.18f;
 | 
			
		||||
	constexpr float hurt_duration = 0.5f;
 | 
			
		||||
	constexpr float invincible_duration = 1.5f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Player::Player()
 | 
			
		||||
@ -42,6 +47,7 @@ void Player::update()
 | 
			
		||||
 | 
			
		||||
	auto mover = get<Mover>();
 | 
			
		||||
	auto anim = get<Animator>();
 | 
			
		||||
	auto hitbox = get<Collider>();
 | 
			
		||||
	auto was_on_ground = m_on_ground;
 | 
			
		||||
	m_on_ground = mover->on_ground();
 | 
			
		||||
	int input = input_move.value_i().x;
 | 
			
		||||
@ -57,7 +63,6 @@ void Player::update()
 | 
			
		||||
 | 
			
		||||
		// set m_facing
 | 
			
		||||
		anim->scale.x = Calc::abs(anim->scale.x) * m_facing;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// NORMAL STATE
 | 
			
		||||
@ -117,7 +122,11 @@ void Player::update()
 | 
			
		||||
			input_attack.clear_press_buffer();
 | 
			
		||||
 | 
			
		||||
			m_state = st_attack;
 | 
			
		||||
			m_attack_timer = anim->sprite()->get_animation("attack")->duration();
 | 
			
		||||
			m_attack_timer = 0;
 | 
			
		||||
 | 
			
		||||
			if (!m_attack_collider)
 | 
			
		||||
				m_attack_collider = entity()->add(Collider::make_rect(RectI()));
 | 
			
		||||
			m_attack_collider->mask = Mask::player_attack;
 | 
			
		||||
 | 
			
		||||
			if (m_on_ground)
 | 
			
		||||
				mover->speed.x = 0;
 | 
			
		||||
@ -127,14 +136,47 @@ void Player::update()
 | 
			
		||||
	else if (m_state == st_attack)
 | 
			
		||||
	{
 | 
			
		||||
		anim->play("attack");
 | 
			
		||||
		m_attack_timer -= Time::delta;
 | 
			
		||||
		m_attack_timer += Time::delta;
 | 
			
		||||
 | 
			
		||||
		if (m_attack_timer <= 0)
 | 
			
		||||
		// setup hitbox
 | 
			
		||||
		if (m_attack_timer < 0.2f)
 | 
			
		||||
		{
 | 
			
		||||
			m_attack_collider->set_rect(RectI(-16, -12, 16, 8));
 | 
			
		||||
		}
 | 
			
		||||
		else if (m_attack_timer < 0.5f)
 | 
			
		||||
		{
 | 
			
		||||
			m_attack_collider->set_rect(RectI(8, -8, 16, 8));
 | 
			
		||||
		}
 | 
			
		||||
		else if (m_attack_collider)
 | 
			
		||||
		{
 | 
			
		||||
			m_attack_collider->destroy();
 | 
			
		||||
			m_attack_collider = nullptr;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// flip hitbox if you're facing left
 | 
			
		||||
		if (m_facing < 0 && m_attack_collider)
 | 
			
		||||
		{
 | 
			
		||||
			auto rect = m_attack_collider->get_rect();
 | 
			
		||||
			rect.x = -(rect.x + rect.w);
 | 
			
		||||
			m_attack_collider->set_rect(rect);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// end the attack
 | 
			
		||||
		if (m_attack_timer >= anim->animation()->duration())
 | 
			
		||||
		{
 | 
			
		||||
			anim->play("idle");
 | 
			
		||||
			m_state = st_normal;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// HURT STATE
 | 
			
		||||
	else if (m_state == st_hurt)
 | 
			
		||||
	{
 | 
			
		||||
		m_hurt_timer -= Time::delta;
 | 
			
		||||
		if (m_hurt_timer <= 0)
 | 
			
		||||
			m_state = st_normal;
 | 
			
		||||
 | 
			
		||||
		mover->speed.x = Calc::approach(mover->speed.x, 0, hurt_friction * Time::delta);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Variable Jumping
 | 
			
		||||
	if (m_jump_timer > 0)
 | 
			
		||||
@ -145,13 +187,44 @@ void Player::update()
 | 
			
		||||
			m_jump_timer = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Invincible timer
 | 
			
		||||
	if (m_state != st_hurt && m_invincible_timer > 0)
 | 
			
		||||
	{
 | 
			
		||||
		if (Time::on_interval(0.05f))
 | 
			
		||||
			anim->visible = !anim->visible;
 | 
			
		||||
 | 
			
		||||
		m_invincible_timer -= Time::delta;
 | 
			
		||||
		if (m_invincible_timer <= 0)
 | 
			
		||||
			anim->visible = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Gravity
 | 
			
		||||
	if (!m_on_ground)
 | 
			
		||||
	{
 | 
			
		||||
		float grav = gravity;
 | 
			
		||||
		if (Calc::abs(mover->speed.y) < 20 && input_jump.down())
 | 
			
		||||
		if (m_state == st_normal && Calc::abs(mover->speed.y) < 20 && input_jump.down())
 | 
			
		||||
			grav *= 0.4f;
 | 
			
		||||
 | 
			
		||||
		mover->speed.y += grav * Time::delta;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Hurt Check!
 | 
			
		||||
	if (m_invincible_timer <= 0 && hitbox->check(Mask::enemy))
 | 
			
		||||
	{
 | 
			
		||||
		Time::pause_for(0.1f);
 | 
			
		||||
		anim->play("hurt");
 | 
			
		||||
 | 
			
		||||
		if (m_attack_collider)
 | 
			
		||||
		{
 | 
			
		||||
			m_attack_collider->destroy();
 | 
			
		||||
			m_attack_collider = nullptr;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		mover->speed = Vec2(-m_facing * 100, -80);
 | 
			
		||||
 | 
			
		||||
		health--;
 | 
			
		||||
		m_hurt_timer = hurt_duration;
 | 
			
		||||
		m_invincible_timer = invincible_duration;
 | 
			
		||||
		m_state = st_hurt;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -6,11 +6,15 @@ using namespace Blah;
 | 
			
		||||
 | 
			
		||||
namespace TL
 | 
			
		||||
{
 | 
			
		||||
	class Collider;
 | 
			
		||||
	class Player : public Component
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		static constexpr int st_normal = 0;
 | 
			
		||||
		static constexpr int st_attack = 1;
 | 
			
		||||
		static constexpr int st_hurt = 2;
 | 
			
		||||
 | 
			
		||||
		int health = 3;
 | 
			
		||||
 | 
			
		||||
		VirtualStick input_move;
 | 
			
		||||
		VirtualButton input_jump;
 | 
			
		||||
@ -24,6 +28,9 @@ namespace TL
 | 
			
		||||
		int m_facing = 1;
 | 
			
		||||
		float m_jump_timer = 0;
 | 
			
		||||
		float m_attack_timer = 0;
 | 
			
		||||
		float m_hurt_timer = 0;
 | 
			
		||||
		float m_invincible_timer = 0;
 | 
			
		||||
		Collider* m_attack_collider = nullptr;
 | 
			
		||||
		bool m_on_ground;
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								src/components/timer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/components/timer.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
			
		||||
#include "timer.h"
 | 
			
		||||
 | 
			
		||||
using namespace TL;
 | 
			
		||||
 | 
			
		||||
Timer::Timer(float duration, const std::function<void(Timer* self)>& on_end)
 | 
			
		||||
	: m_duration(duration), on_end(on_end)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Timer::start(float duration)
 | 
			
		||||
{
 | 
			
		||||
	m_duration = duration;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Timer::update()
 | 
			
		||||
{
 | 
			
		||||
	if (m_duration > 0)
 | 
			
		||||
	{
 | 
			
		||||
		m_duration -= Time::delta;
 | 
			
		||||
		if (m_duration <= 0 && on_end)
 | 
			
		||||
		{
 | 
			
		||||
			on_end(this);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								src/components/timer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/components/timer.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "../world.h"
 | 
			
		||||
#include <blah.h>
 | 
			
		||||
#include <functional>
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
namespace TL
 | 
			
		||||
{
 | 
			
		||||
	class Timer : public Component
 | 
			
		||||
	{
 | 
			
		||||
	private:
 | 
			
		||||
		float m_duration = 0;
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		Timer() = default;
 | 
			
		||||
		Timer(float duration, const std::function<void(Timer* self)>& on_end = nullptr);
 | 
			
		||||
 | 
			
		||||
		void start(float duration);
 | 
			
		||||
		std::function<void(Timer* self)> on_end;
 | 
			
		||||
 | 
			
		||||
		void update() override;
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
@ -1,8 +1,11 @@
 | 
			
		||||
#include "factory.h"
 | 
			
		||||
#include "masks.h"
 | 
			
		||||
#include "components/animator.h"
 | 
			
		||||
#include "components/collider.h"
 | 
			
		||||
#include "components/mover.h"
 | 
			
		||||
#include "components/player.h"
 | 
			
		||||
#include "components/hurtable.h"
 | 
			
		||||
#include "components/timer.h"
 | 
			
		||||
 | 
			
		||||
using namespace TL;
 | 
			
		||||
 | 
			
		||||
@ -22,3 +25,44 @@ Entity* Factory::player(World* world, Point position)
 | 
			
		||||
	en->add(Player());
 | 
			
		||||
	return en;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Entity* Factory::bramble(World* world, Point position)
 | 
			
		||||
{
 | 
			
		||||
	auto en = world->add_entity(position);
 | 
			
		||||
 | 
			
		||||
	auto anim = en->add(Animator("bramble"));
 | 
			
		||||
	anim->play("idle");
 | 
			
		||||
	anim->depth = -5;
 | 
			
		||||
 | 
			
		||||
	auto hitbox = en->add(Collider::make_rect(RectI(-4, -8, 8, 8)));
 | 
			
		||||
	hitbox->mask = Mask::enemy;
 | 
			
		||||
 | 
			
		||||
	auto hurtable = en->add(Hurtable());
 | 
			
		||||
	hurtable->hurt_by = Mask::player_attack;
 | 
			
		||||
	hurtable->collider = hitbox;
 | 
			
		||||
	hurtable->on_hurt = [](Hurtable* self)
 | 
			
		||||
	{
 | 
			
		||||
		Time::pause_for(0.1f);
 | 
			
		||||
		pop(self->world(), self->entity()->position + Point(0, -4));
 | 
			
		||||
		self->entity()->destroy();
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	return en;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Entity* Factory::pop(World* world, Point position)
 | 
			
		||||
{
 | 
			
		||||
	auto en = world->add_entity(position);
 | 
			
		||||
 | 
			
		||||
	auto anim = en->add(Animator("pop"));
 | 
			
		||||
	anim->play("pop");
 | 
			
		||||
	anim->depth = -20;
 | 
			
		||||
 | 
			
		||||
	auto timer = en->add(Timer(anim->animation()->duration(), [](Timer* self)
 | 
			
		||||
		{
 | 
			
		||||
			self->entity()->destroy();
 | 
			
		||||
		}));
 | 
			
		||||
 | 
			
		||||
	return en;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -9,5 +9,7 @@ namespace TL
 | 
			
		||||
	namespace Factory
 | 
			
		||||
	{
 | 
			
		||||
		Entity* player(World* world, Point position);
 | 
			
		||||
		Entity* bramble(World* world, Point position);
 | 
			
		||||
		Entity* pop(World* world, Point position);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										17
									
								
								src/game.cpp
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								src/game.cpp
									
									
									
									
									
								
							@ -11,7 +11,7 @@ using namespace TL;
 | 
			
		||||
 | 
			
		||||
namespace
 | 
			
		||||
{
 | 
			
		||||
	constexpr float transition_duration = 0.75f;
 | 
			
		||||
	constexpr float transition_duration = 0.4f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Game::startup()
 | 
			
		||||
@ -91,6 +91,11 @@ void Game::load_room(Point cell)
 | 
			
		||||
				if (!world.first<Player>())
 | 
			
		||||
					Factory::player(&world, world_position + Point(tile_width / 2, tile_height));
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			// brambles
 | 
			
		||||
			case 0xd77bba:
 | 
			
		||||
				Factory::bramble(&world, world_position + Point(tile_width / 2, tile_height));
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
}
 | 
			
		||||
@ -134,6 +139,8 @@ void Game::update()
 | 
			
		||||
				// see if room exists
 | 
			
		||||
				if (Content::find_room(next_room))
 | 
			
		||||
				{
 | 
			
		||||
					Time::pause_for(0.1f);
 | 
			
		||||
 | 
			
		||||
					// transiton to it!
 | 
			
		||||
					m_transition = true;
 | 
			
		||||
					m_next_ease = 0;
 | 
			
		||||
@ -165,12 +172,17 @@ void Game::update()
 | 
			
		||||
	// Room Transition routine
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		// increment ease
 | 
			
		||||
		m_next_ease = Calc::approach(m_next_ease, 1.0f, Time::delta / transition_duration);
 | 
			
		||||
 | 
			
		||||
		// get last & next camera position
 | 
			
		||||
		auto last_cam = Vec2(m_last_room.x * width, m_last_room.y * height);
 | 
			
		||||
		auto next_cam = Vec2(m_next_room.x * width, m_next_room.y * height);
 | 
			
		||||
 | 
			
		||||
		m_next_ease = Calc::approach(m_next_ease, 1.0f, Time::delta / transition_duration);
 | 
			
		||||
		// LERP camera position
 | 
			
		||||
		camera = last_cam + (next_cam - last_cam) * Ease::cube_in_out(m_next_ease);
 | 
			
		||||
 | 
			
		||||
		// Finish Transition
 | 
			
		||||
		if (m_next_ease >= 1.0f)
 | 
			
		||||
		{
 | 
			
		||||
			// delete old objects (except player!)
 | 
			
		||||
@ -180,6 +192,7 @@ void Game::update()
 | 
			
		||||
					world.destroy_entity(it);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			Time::pause_for(0.1f);
 | 
			
		||||
			m_transition = false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -6,5 +6,7 @@ namespace TL
 | 
			
		||||
	struct Mask
 | 
			
		||||
	{
 | 
			
		||||
		static constexpr uint32_t solid = 1 << 0;
 | 
			
		||||
		static constexpr uint32_t player_attack = 1 << 1;
 | 
			
		||||
		static constexpr uint32_t enemy = 1 << 2;
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
@ -97,6 +97,11 @@ Blah::Vector<Component*>& Entity::components()
 | 
			
		||||
	return m_components;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Entity::destroy()
 | 
			
		||||
{
 | 
			
		||||
	m_world->destroy_entity(this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Blah::Vector<Component*>& Entity::components() const
 | 
			
		||||
{
 | 
			
		||||
	return m_components;
 | 
			
		||||
 | 
			
		||||
@ -95,6 +95,8 @@ namespace TL
 | 
			
		||||
 | 
			
		||||
		Blah::Vector<Component*>& components();
 | 
			
		||||
		const Blah::Vector<Component*>& components() const;
 | 
			
		||||
		
 | 
			
		||||
		void destroy();
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		Blah::Vector<Component*> m_components;
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user