Commit 115bf766 authored by 魔大农's avatar 魔大农 🍀

Giant leap

parent 32b21173
No preview for this file type
# [:four_leaf_clover:] (http://www.luckeyproductions.nl/) Quatter
A digital version of [the Quarto boardgame](https://en.wikipedia.org/wiki/Quarto_%28board_game%29) by Blaise Müller, made using the Urho3D game engine.
![A rendered image of the board](https://raw.githubusercontent.com/Modanung/Quatter/master/Blends/Render/2.png)
\ No newline at end of file
![Screenshot](https://raw.githubusercontent.com/Modanung/Quatter/master/Screenshots/Screenshot_Wed_May_25_04_42_57_2016.png)
\ No newline at end of file
This diff is collapsed.
<?xml version="1.0"?>
<material>
<technique name="Techniques/DiffNormalSpec.xml" quality="1" loddistance="0" />
<texture unit="diffuse" name="Resources/Textures/BoardDiffuse.png" />
<texture unit="normal" name="Resources/Textures/BoardNormal.png" />
<texture unit="specular" name="Resources/Textures/BoardSpecular.png" />
<technique name="Techniques/DiffNormalEnvCube.xml" quality="1" loddistance="0" />
<texture unit="diffuse" name="Textures/BoardDiffuse.png" />
<texture unit="normal" name="Textures/BoardNormal.png" />
<texture unit="specular" name="Textures/BoardSpecular.png" />
<texture unit="environment" name="Textures/LeafyKnoll.xml" />
<parameter name="UOffset" value="1 0 0 0" />
<parameter name="VOffset" value="0 1 0 0" />
<parameter name="MatDiffColor" value="1 1 1 1" />
<parameter name="MatEmissiveColor" value="0 0 0" />
<parameter name="MatEnvMapColor" value="1 1 1" />
<parameter name="MatSpecColor" value="0.666 0.666 0.666 23" />
<parameter name="MatEnvMapColor" value="0.05 0.05 0.05" />
<parameter name="MatSpecColor" value=".34 .34 .34 5" />
<cull value="ccw" />
<shadowcull value="ccw" />
<fill value="solid" />
......
<?xml version="1.0"?>
<material>
<technique name="Techniques/PBR/PBRDiffNormalEnvMap.xml" quality="0" loddistance="0" />
<texture unit="diffuse" name="Textures/BoardDiffuse.png" />
<texture unit="normal" name="Textures/BoardNormal.png" />
<texture unit="specular" name="Textures/BoardSpecular.png" />
<texture unit="environment" name="Textures/LeafyKnoll.xml" />
<parameter name="UOffset" value="1 0 0 0" />
<parameter name="VOffset" value="0 1 0 0" />
<parameter name="RoughnessPS" value="0.1" />
<parameter name="MetallicPS" value="0" />
<cull value="ccw" />
<shadowcull value="ccw" />
<fill value="solid" />
<depthbias constant="0" slopescaled="0" />
<renderorder value="128" />
</material>
<?xml version="1.0"?>
<material>
<technique name="Techniques/DiffSkybox.xml" quality="0" loddistance="0" />
<texture unit="diffuse" name="Textures/LeafyKnollPng.xml" />
<parameter name="UOffset" value="1 0 0 0" />
<parameter name="VOffset" value="0 1 0 0" />
<parameter name="MatDiffColor" value="0.666 0.666 0.666 1" />
<parameter name="MatEmissiveColor" value="0 0 0" />
<parameter name="MatEnvMapColor" value="1 1 1" />
<parameter name="MatSpecColor" value="0 0 0 1" />
<parameter name="RoughnessPS" value="0.5" />
<parameter name="MetallicPS" value="0" />
<cull value="none" />
<shadowcull value="ccw" />
<fill value="solid" />
<depthbias constant="0" slopescaled="0" />
<renderorder value="128" />
</material>
<material>
<technique name="Techniques/DiffNormalPackedEnvCube.xml" quality="1" />
<technique name="Techniques/Diff.xml" quality="0" />
<texture unit="diffuse" name="Textures/StoneDiffuse.dds" />
<texture unit="normal" name="Textures/StoneNormal.dds" />
<texture unit="environment" name="Textures/LeafyKnoll.xml" />
<parameter name="MatEnvMapColor" value="0.08 0.08 0.08" />
<parameter name="MatSpecColor" value="0.3 0.3 0.3 16" />
</material>
\ No newline at end of file
......@@ -5,6 +5,6 @@
<parameter name="VOffset" value="0 1 0 0" />
<parameter name="MatDiffColor" value="0.25 0.19 0.14 1" />
<parameter name="MatEmissiveColor" value="0 0 0" />
<parameter name="MatEnvMapColor" value="1 1 1" />
<parameter name="MatEnvMapColor" value="0.05 0.05 0.05" />
<parameter name="MatSpecColor" value="0.32 0.35 0.3 5" />
</material>
This diff is collapsed.
<cubemap>
<face name="LeafyKnoll_PosX.dds" />
<face name="LeafyKnoll_NegX.dds" />
<face name="LeafyKnoll_PosY.dds" />
<face name="LeafyKnoll_NegY.dds" />
<face name="LeafyKnoll_PosZ.dds" />
<face name="LeafyKnoll_NegZ.dds" />
<!--quality low="0" /-->
</cubemap>
\ No newline at end of file
<cubemap>
<face name="East.png" />
<face name="West.png" />
<face name="Up.png" />
<face name="Down.png" />
<face name="North.png" />
<face name="South.png" />
<quality low="0" />
</cubemap>
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#include "board.h"
Board::Board(): Object(MC->GetContext())
namespace Urho3D {
template <> unsigned MakeHash(const IntVector2& value)
{
return LucKey::IntVector2ToHash(value);
}
}
Board::Board(): Object(MC->GetContext()),
squares_{}
{
Node* rootNode = MC->world.scene->CreateChild("Board");
model_ = rootNode->CreateComponent<StaticModel>();
model_->SetModel(MC->cache_->GetResource<Model>("Resources/Models/Board.mdl"));
model_->SetMaterial(MC->cache_->GetResource<Material>("Resources/Materials/Board.xml"));
model_->SetCastShadows(true);
for (int i{0}; i < BOARD_HEIGHT; ++i)
for (int j{0}; j < BOARD_WIDTH; ++j){
Square square{};
square.coords_ = IntVector2(i, j);
square.node_ = rootNode->CreateChild("Square");
square.node_->SetPosition(SquarePosition(square.coords_));
Node* lightNode{square.node_->CreateChild("Light")};
lightNode->SetPosition(Vector3::UP * 0.23f);
square.light_ = square.node_->CreateComponent<Light>();
square.light_->SetColor(Color(0.0f, 0.8f, 0.5f));
square.light_->SetBrightness(0.5f);
square.light_->SetRange(5.0f);
square.light_->SetEnabled(false);
StaticModel* slotModel{square.node_->CreateComponent<StaticModel>()};
// slotModel->SetModel(MC->GetModel("Slot")->Clone());
// slotModel->SetMaterial(MC->GetMaterial("Slot.xml"));
slotModel->SetCastShadows(true);
squares_[square.coords_] = square;
}
}
Vector3 Board::SquarePosition(IntVector2 coords)
{
return Vector3(0.5f + coords.x_ - BOARD_WIDTH/2,
0.0f,
0.5f + coords.y_ - BOARD_HEIGHT/2);
}
bool Board::CheckQuatter()
{
//Check rows
for (int i{0}; i < BOARD_HEIGHT; ++i){
Piece::Attributes matching{NUM_PIECES - 1};
Piece::Attributes first{};
for (int j{0}; j < BOARD_WIDTH; ++j){
IntVector2 coords(i, j);
if (squares_[coords].piece_){
auto attributes(squares_[coords].piece_->GetAttributes());
if (j == 0) {
first = attributes;
} else {
for (int a{0}; a < NUM_ATTRIBUTES; ++a)
if (first[a] != attributes[a])
matching[a] = false;
}
//Full row required
} else {
matching.reset();
break;
}
}
//Quatter!
if (matching.any()){
return true;
}
}
//Check columns
for (int j{0}; j < BOARD_WIDTH; ++j){
Piece::Attributes matching{NUM_PIECES - 1};
Piece::Attributes first{};
for (int i{0}; i < BOARD_HEIGHT; ++i){
IntVector2 coords(i, j);
if (squares_[coords].piece_){
auto attributes(squares_[coords].piece_->GetAttributes());
if (j == 0) {
first = attributes;
} else {
for (int a{0}; a < NUM_ATTRIBUTES; ++a)
if (first[a] != attributes[a])
matching[a] = false;
}
//Full column required
} else {
matching.reset();
break;
}
}
//Quatter!
if (matching.any()){
return true;
}
}
//Check diagonals
for (bool direction : {true, false}){
Piece::Attributes matching{NUM_PIECES - 1};
Piece::Attributes first{};
for (int i{0}; i < BOARD_WIDTH; ++i){
IntVector2 coords(i, direction ? i : (BOARD_WIDTH - i - 1));
if (squares_[coords].piece_){
auto attributes(squares_[coords].piece_->GetAttributes());
if (i == 0) {
first = attributes;
} else {
for (int a{0}; a < NUM_ATTRIBUTES; ++a)
if (first[a] != attributes[a])
matching[a] = false;
}
//Full line required
} else {
matching.reset();
break;
}
}
//Quatter!
if (matching.any()){
return true;
}
}
//Check blocks
for (int k{0}; k < BOARD_WIDTH - 1; ++k){
for (int l{0}; l < BOARD_HEIGHT - 1; ++l){
Piece::Attributes matching{NUM_PIECES - 1};
Piece::Attributes first{};
for (int m : {0, 1}) for (int n : {0, 1}){
IntVector2 coords(k + m, l + n);
if (squares_[coords].piece_){
auto attributes(squares_[coords].piece_->GetAttributes());
if (m == 0 && n == 0) {
first = attributes;
} else {
for (int a{0}; a < NUM_ATTRIBUTES; ++a)
if (first[a] != attributes[a])
matching[a] = false;
}
//Full line required
} else {
matching.reset();
break;
}
}
//Quatter!
if (matching.any()){
return true;
}
}
}
//No Quatter
return false;
}
......@@ -11,14 +11,28 @@ class Node;
using namespace Urho3D;
#define BOARD_WIDTH 4
#define BOARD_HEIGHT 4
typedef struct Square{
IntVector2 coords_;
SharedPtr<Node> node_;
SharedPtr<Light> light_;
Piece* piece_;
}Square;
class Board : public Object
{
URHO3D_OBJECT(Board, Object);
public:
Board();
float GetHeight() const { return model_->GetBoundingBox().Size().y_; }
float GetThickness() const { return model_->GetBoundingBox().Size().y_; }
bool CheckQuatter();
private:
StaticModel* model_;
HashMap<IntVector2, Square> squares_;
Vector3 SquarePosition(IntVector2 coords);
};
#endif // BOARD_H
#include "inputmaster.h"
#include "quattercam.h"
#include "piece.h"
InputMaster::InputMaster() : Master(),
input_{GetSubsystem<Input>()}
input_{GetSubsystem<Input>()},
idle_{false}
{
SubscribeToEvent(E_MOUSEBUTTONDOWN, URHO3D_HANDLER(InputMaster, HandleMouseButtonDown));
SubscribeToEvent(E_MOUSEBUTTONUP, URHO3D_HANDLER(InputMaster, HandleMouseButtonUp));
......@@ -91,11 +93,35 @@ void InputMaster::HandleUpdate(StringHash eventType, VariantMap &eventData)
float t{eventData[Update::P_TIMESTEP].GetFloat()};
idleTime_ += t;
if (input_->GetMouseButtonDown(1)){
Vector2 camRot{};
float camZoom{};
float keyRotMultiplier{0.5f};
float keyZoomSpeed{0.1f};
if (pressedKeys_.Size()) idleTime_ = 0.0f;
for (int key : pressedKeys_){
switch (key){
case KEY_A:{ camRot += keyRotMultiplier * Vector2::RIGHT;
} break;
case KEY_D:{ camRot += keyRotMultiplier * Vector2::LEFT;
} break;
case KEY_W:{ camRot += keyRotMultiplier * Vector2::UP;
} break;
case KEY_S:{ camRot += keyRotMultiplier * Vector2::DOWN;
} break;
case KEY_Q:{ camZoom += keyZoomSpeed;
} break;
case KEY_E:{ camZoom += -keyZoomSpeed;
} break;
default: break;
}
}
if (input_->GetMouseButtonDown(MOUSEB_RIGHT)){
idleTime_ = 0.0f;
IntVector2 mouseMove = input_->GetMouseMove();
Vector2 rotation = Vector2(mouseMove.x_, mouseMove.y_) * 0.1f;
MC->world.camera->Rotate(rotation);
camRot += Vector2(mouseMove.x_, mouseMove.y_) * 0.1f;
}
//Should check whose turn it is
JoystickState* joy0 = input_->GetJoystickByIndex(0);
......@@ -103,11 +129,29 @@ void InputMaster::HandleUpdate(StringHash eventType, VariantMap &eventData)
Vector2 rotation{-Vector2(joy0->GetAxisPosition(2), joy0->GetAxisPosition(3))};
if (rotation.Length()){
idleTime_ = 0.0f;
MC->world.camera->Rotate(rotation);
camRot += rotation * t * 42.0f;
}
camZoom += t * (joy0->GetAxisPosition(12) - joy0->GetAxisPosition(13));
}
float idleThreshold{5.0f};
if (idleTime_ > idleThreshold)
MC->world.camera->Rotate(Vector2::LEFT * Min((idleTime_ - idleThreshold) * 0.0023f, 0.005f));
float idleStartup{Min(0.5f * (idleTime_ - idleThreshold), 1.0f)};
if (idleTime_ > idleThreshold){
if (!idle_) {
idle_ = true;
for (Piece* p: MC->world.pieces_){
p->Deselect();
}
}
camRot += Vector2(t * idleStartup * -0.5f,
t * idleStartup * MC->Sine(0.23f, -0.042f, 0.042f));
} else {
if (idle_) idle_ = false;
}
smoothCamRotate_ = 0.1f * (camRot + smoothCamRotate_ * 9.0f);
smoothCamZoom_ = 0.1f * (camZoom + smoothCamZoom_ * 9.0f);
CAMERA->Rotate(smoothCamRotate_);
CAMERA->Zoom(smoothCamZoom_);
}
......@@ -5,16 +5,23 @@
enum class JoystickButton {SELECT, LEFTSTICK, RIGHTSTICK, START, DPAD_UP, DPAD_RIGHT, DPAD_DOWN, DPAD_LEFT, L2, R2, L1, R1, TRIANGLE, CIRCLE, CROSS, SQUARE};
#define CAMERA MC->world.camera
class InputMaster : public Master
{
URHO3D_OBJECT(InputMaster, Master);
public:
InputMaster();
WeakPtr<Node> firstHit_;
bool IsIdle() const noexcept { return idle_; }
private:
Input* input_;
float idleTime_;
bool idle_;
Vector2 smoothCamRotate_;
float smoothCamZoom_;
HashSet<int> pressedKeys_;
HashSet<int> pressedMouseButtons_;
......
......@@ -18,6 +18,21 @@
#include "luckey.h"
float LucKey::Delta(float lhs, float rhs, bool angle)
{
if (!angle)
return (lhs > rhs) ? Abs(lhs - rhs) : Abs(rhs - lhs);
else {
lhs = Cycle(lhs, 0.0f, 360.0f);
rhs = Cycle(rhs, 0.0f, 360.0f);
if (Delta(lhs, rhs) > 180.0f)
return Abs(360.0f - Delta(lhs, rhs));
else
return Delta(lhs, rhs);
}
}
float LucKey::Distance(const Vector3 from, const Vector3 to){
return (to - from).Length();
}
......@@ -33,13 +48,13 @@ Urho3D::IntVector2 LucKey::Scale(const Urho3D::IntVector2 lhs, const Urho3D::Int
}
Vector2 LucKey::Rotate(const Vector2 vec2, const float angle){
float x = vec2.x_;
float y = vec2.y_;
float x{vec2.x_};
float y{vec2.y_};
float theta = M_DEGTORAD * angle;
float theta{M_DEGTORAD * angle};
float cs = cos(theta);
float sn = sin(theta);
float cs{cos(theta)};
float sn{sin(theta)};
return Vector2(x * cs - y * sn, x * sn + y * cs);
}
......@@ -68,3 +83,34 @@ Color LucKey::RandomColor()
color.FromHSV(Random(), Random(), Random());
return color;
}
float LucKey::Sine(float x)
{
if (x < -M_PI){
while (x < -M_PI) {
x += 2.0f * M_PI;
}
} else while (x > M_PI) {
x -= 2.0f * M_PI;
}
float sin{};
if (x < 0.0f)
sin = 1.27323954f * x + 0.405284735f * x * x;
else
sin = 1.27323954f * x - 0.405284735f * x * x;
if (sin < 0)
sin = 0.225f * (sin *-sin - sin) + sin;
else
sin = 0.225f * (sin * sin - sin) + sin;
return sin;
}
float LucKey::Cosine(float x)
{
return Sine(x + M_PI * 0.5f);
}
......@@ -88,6 +88,7 @@ T Cycle(T x, T min, T max){
: x;
}
float Delta(float lhs, float rhs, bool angle = false);
float Distance(const Vector3 from, const Vector3 to);
unsigned IntVector2ToHash(IntVector2 vec);
Vector3 Scale(const Vector3 lhs, const Vector3 rhs);
......@@ -97,6 +98,9 @@ float RandomSign();
Color RandomColor();
Color RandomSkinColor();
Color RandomHairColor();
float Sine(float x);
float Cosine(float x);
}
#endif // LUCKEY_H
......@@ -33,7 +33,7 @@ void MasterControl::Setup()
}
void MasterControl::Start()
{
new InputMaster();
inputMaster_ = new InputMaster();
cache_ = GetSubsystem<ResourceCache>();
CreateScene();
......@@ -46,6 +46,8 @@ void MasterControl::Start()
musicSource_->SetSoundType(SOUND_MUSIC);
musicSource_->SetGain(musicGain_);
musicSource_->Play(music);
SubscribeToEvent(E_UPDATE, URHO3D_HANDLER(MasterControl, HandleUpdate));
}
void MasterControl::Stop()
{
......@@ -53,6 +55,9 @@ void MasterControl::Stop()
}
void MasterControl::Exit()
{
File file(context_, "Resources/Endgame.xml", FILE_WRITE);
world.scene->SaveXML(file);
engine_->Exit();
}
......@@ -60,27 +65,32 @@ void MasterControl::CreateScene()
{
world.scene = new Scene(context_);
world.scene->CreateComponent<Octree>();
world.camera = new QuatterCam();
CreateLights();
//Create skybox
Node* skyNode = world.scene->CreateChild("Sky");
Skybox* skybox = skyNode->CreateComponent<Skybox>();
skybox->SetModel(GetModel("Box"));
skybox->SetMaterial(GetMaterial("LeafyKnoll"));
world.camera = new QuatterCam();
//Create table
Node* tableNode = world.scene->CreateChild("Table");
tableNode->SetRotation(Quaternion(23.5f, Vector3::UP));
tableNode->SetScale(19.0f);
// tableNode->SetScale(19.0f);
StaticModel* tableModel = tableNode->CreateComponent<StaticModel>();
tableModel->SetModel(cache_->GetResource<Model>("Models/Plane.mdl"));
tableModel->SetMaterial(cache_->GetResource<Material>("Materials/Stone.xml"));
tableModel->SetModel(GetModel("Table"));
tableModel->SetMaterial(GetMaterial("Table"));
tableModel->GetMaterial()->SetShaderParameter("MatDiffColor", Vector4(0.32f, 0.40f, 0.42f, 1.0f));
//Create board and pieces
world.board_ = new Board();
tableNode->SetPosition(Vector3::DOWN * world.board_->GetHeight());
for (int p = 0; p < 16; ++p){
Piece* newPiece = new Piece(std::bitset<4>(p));
for (int p{0}; p < NUM_PIECES; ++p){
Piece* newPiece = new Piece(Piece::Attributes(p));
world.pieces_.Push(SharedPtr<Piece>(newPiece));
newPiece->SetPosition(Quaternion(360.0f/16 * p, Vector3::UP) * Vector3::RIGHT * 6.66f +
Vector3::DOWN * world.board_->GetHeight());
newPiece->SetPosition(AttributesToPosition(p));
}
}
......@@ -110,6 +120,20 @@ void MasterControl::CreateLights()
pointLight->SetColor(Color(0.75f, 1.0f, 0.75f));
}
void MasterControl::HandleUpdate(StringHash eventType, VariantMap& eventData)
{
// float t{eventData[Update::P_TIMESTEP].GetFloat()};
if (!inputMaster_->IsIdle()){
for (Piece* p: world.pieces_){
if (LucKey::Delta(CAMERA->GetYaw(), p->GetAngle(), true) < 180.0f / NUM_PIECES){
p->Select();
} else {
p->Deselect();
}
}
}
}
void MasterControl::NextPhase()
{
switch (gamePhase_) {
......@@ -126,21 +150,24 @@ void MasterControl::NextPhase()
void MasterControl::ToggleMusic()
{
ValueAnimation* fade{musicSource_->GetAttributeAnimation("Gain")};
float fadeEndValue{-1.0f};
if (fade)
fadeEndValue = fade->GetAnimationValue(fade->GetEndTime()).GetFloat();
if (musicSource_->GetGain() == 0.0f){
if (musicSource_->GetGain() == 0.0f || fadeEndValue == 0.0f){
ValueAnimation* fadeIn_{new ValueAnimation(context_)};
fadeIn_->SetKeyFrame(0.0f, 0.0f);
fadeIn_->SetKeyFrame(1.0f, 0.5f * musicGain_);
fadeIn_->SetKeyFrame(2.3f, musicGain_);
fadeIn_->SetKeyFrame(2.3f, Min(musicGain_, 0.1f));
musicSource_->SetAttributeAnimation("Gain", fadeIn_, WM_ONCE);
}
else{
musicGain_ = musicSource_->GetGain();
float lastGain_{musicSource_->GetGain()};
ValueAnimation* fadeOut_ = new ValueAnimation(context_);
fadeOut_->SetKeyFrame(0.0f, musicGain_);
fadeOut_->SetKeyFrame(1.0f, 0.5f * musicGain_);
fadeOut_->SetKeyFrame(2.3f, 0.1f * musicGain_);
fadeOut_->SetKeyFrame(0.0f, lastGain_);
fadeOut_->SetKeyFrame(1.0f, 0.5f * lastGain_);
fadeOut_->SetKeyFrame(2.3f, 0.1f * lastGain_);
fadeOut_->SetKeyFrame(5.0f, 0.0f);
musicSource_->SetAttributeAnimation("Gain", fadeOut_, WM_ONCE);
}
......@@ -148,7 +175,7 @@ void MasterControl::ToggleMusic()
void MasterControl::MusicGainUp(float step)
{
musicGain_ = Clamp(musicGain_ + step, 0.0f, 1.0f);
musicGain_ = Clamp(musicGain_ + step, step, 1.0f);
ValueAnimation* fadeIn_{new ValueAnimation(context_)};
fadeIn_->SetKeyFrame(0.0f, musicSource_->GetGain());
......@@ -164,3 +191,16 @@ void MasterControl::MusicGainDown(float step)
fadeOut_->SetKeyFrame(0.23f, musicGain_);
musicSource_->SetAttributeAnimation("Gain", fadeOut_, WM_ONCE);
}
float MasterControl::Sine(const float freq, const float min, const float max, const float shift)
{
float phase{freq * world.scene->GetElapsedTime() + shift};
float add{0.5f * (min + max)};
return LucKey::Sine(phase) * 0.5f * (max - min) + add;
}
float MasterControl::Cosine(const float freq, const float min, const float max, const float shift)
{
float phase{freq * world.scene->GetElapsedTime() + shift};
float add{0.5f * (min + max)};
return LucKey::Cosine(phase) * 0.5f * (max - min) + add;
}
......@@ -33,6 +33,7 @@ typedef struct GameWorld
} cursor;
} GameWorld;
#define NUM_PIECES 16
#define MC MasterControl::GetInstance()
class MasterControl : public Application
......@@ -58,10 +59,21 @@ public:
void CreateLights();
inline GamePhase GetGamePhase() const noexcept { return gamePhase_; }
float AttributesToAngle(int attributes) const { return 360.0f/NUM_PIECES * attributes; }
Vector3 AttributesToPosition(int attributes) const {
return Quaternion(AttributesToAngle(attributes), Vector3::UP) * Vector3::FORWARD * 7.0f
+ Vector3::DOWN * 0.23f;
}
Material* GetMaterial(String name) const { return cache_->GetResource<Material>("Materials/"+name+".xml"); }
Model* GetModel(String name) const { return cache_->GetResource<Model>("Models/"+name+".mdl"); }
float Sine(const float freq, const float min, const float max, const float shift = 0.0f);
float Cosine(const float freq, const float min, const float max, const float shift = 0.0f);
private:
static MasterControl* instance_;
InputMaster* inputMaster_;
SharedPtr<SoundSource> musicSource_;
float musicGain_;
......
#include "piece.h"
Piece::Piece(std::bitset<4> attributes): Object(MC->GetContext()),
state_{PieceState::FREE}
Piece::Piece(Attributes attributes): Object(MC->GetContext()),
state_{PieceState::FREE},
attributes_{attributes}