Refactored sprite & transform. Replaced distance with collider when picking objects up.

This commit is contained in:
Tiberiu Chibici 2016-12-15 22:52:36 +02:00
parent ddae4934ef
commit 42f0d4125b
20 changed files with 273 additions and 208 deletions

View File

@ -29,7 +29,6 @@
</option> </option>
<option id="gnu.cpp.compiler.option.include.paths.1179839838" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" useByScannerDiscovery="false" valueType="includePath"> <option id="gnu.cpp.compiler.option.include.paths.1179839838" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" useByScannerDiscovery="false" valueType="includePath">
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/Farmlands/src}&quot;"/> <listOptionValue builtIn="false" value="&quot;${workspace_loc:/Farmlands/src}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/Farmlands/import/include}&quot;"/>
</option> </option>
<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1411957018" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/> <inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1411957018" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
</tool> </tool>
@ -39,7 +38,6 @@
<option id="gnu.c.compiler.option.dialect.std.1347456933" name="Language standard" superClass="gnu.c.compiler.option.dialect.std" useByScannerDiscovery="true" value="gnu.c.compiler.dialect.c99" valueType="enumerated"/> <option id="gnu.c.compiler.option.dialect.std.1347456933" name="Language standard" superClass="gnu.c.compiler.option.dialect.std" useByScannerDiscovery="true" value="gnu.c.compiler.dialect.c99" valueType="enumerated"/>
<option id="gnu.c.compiler.option.include.paths.1506817800" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths" useByScannerDiscovery="false" valueType="includePath"> <option id="gnu.c.compiler.option.include.paths.1506817800" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths" useByScannerDiscovery="false" valueType="includePath">
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/Farmlands/src}&quot;"/> <listOptionValue builtIn="false" value="&quot;${workspace_loc:/Farmlands/src}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/Farmlands/import/include}&quot;"/>
</option> </option>
<option id="gnu.c.compiler.option.preprocessor.def.symbols.1611927348" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols" useByScannerDiscovery="false" valueType="definedSymbols"> <option id="gnu.c.compiler.option.preprocessor.def.symbols.1611927348" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols" useByScannerDiscovery="false" valueType="definedSymbols">
<listOptionValue builtIn="false" value="BUILD_DEBUG"/> <listOptionValue builtIn="false" value="BUILD_DEBUG"/>
@ -105,7 +103,6 @@
</option> </option>
<option id="gnu.cpp.compiler.option.include.paths.664997027" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" useByScannerDiscovery="false" valueType="includePath"> <option id="gnu.cpp.compiler.option.include.paths.664997027" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" useByScannerDiscovery="false" valueType="includePath">
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/Farmlands/src}&quot;"/> <listOptionValue builtIn="false" value="&quot;${workspace_loc:/Farmlands/src}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/Farmlands/import/include}&quot;"/>
</option> </option>
<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1719824945" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/> <inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1719824945" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
</tool> </tool>
@ -115,7 +112,6 @@
<option id="gnu.c.compiler.option.dialect.std.1246534005" name="Language standard" superClass="gnu.c.compiler.option.dialect.std" useByScannerDiscovery="true" value="gnu.c.compiler.dialect.c99" valueType="enumerated"/> <option id="gnu.c.compiler.option.dialect.std.1246534005" name="Language standard" superClass="gnu.c.compiler.option.dialect.std" useByScannerDiscovery="true" value="gnu.c.compiler.dialect.c99" valueType="enumerated"/>
<option id="gnu.c.compiler.option.include.paths.1574426438" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths" useByScannerDiscovery="false" valueType="includePath"> <option id="gnu.c.compiler.option.include.paths.1574426438" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths" useByScannerDiscovery="false" valueType="includePath">
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/Farmlands/src}&quot;"/> <listOptionValue builtIn="false" value="&quot;${workspace_loc:/Farmlands/src}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/Farmlands/import/include}&quot;"/>
</option> </option>
<option id="gnu.c.compiler.option.preprocessor.def.symbols.252229749" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols" useByScannerDiscovery="false" valueType="definedSymbols"> <option id="gnu.c.compiler.option.preprocessor.def.symbols.252229749" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols" useByScannerDiscovery="false" valueType="definedSymbols">
<listOptionValue builtIn="false" value="BUILD_RELEASE"/> <listOptionValue builtIn="false" value="BUILD_RELEASE"/>

View File

@ -3,21 +3,22 @@
<GameObject name="Ugliceea"> <GameObject name="Ugliceea">
<Transform /> <Transform />
<Sprite name="Ugliceea" anchorX="0" anchorY=".5"> <Sprite w="1" h="2"
anchorX="0" anchorY=".5">
<State name="0"> <State name="0">
<Frame tileSet="plants/graphics/Ugliceea.png" cell="0" w="1" h="2" duration="1" /> <Frame tileSet="plants/graphics/Ugliceea.png" cell="0" duration="1" />
</State> </State>
<State name="1"> <State name="1">
<Frame tileSet="plants/graphics/Ugliceea.png" cell="1" w="1" h="2" duration="1" /> <Frame tileSet="plants/graphics/Ugliceea.png" cell="1" duration="1" />
</State> </State>
<State name="2"> <State name="2">
<Frame tileSet="plants/graphics/Ugliceea.png" cell="2" w="1" h="2" duration="1" /> <Frame tileSet="plants/graphics/Ugliceea.png" cell="2" duration="1" />
</State> </State>
<State name="3"> <State name="3">
<Frame tileSet="plants/graphics/Ugliceea.png" cell="3" w="1" h="2" duration="1" /> <Frame tileSet="plants/graphics/Ugliceea.png" cell="3" duration="1" />
</State> </State>
<State name="4"> <State name="4">
<Frame tileSet="plants/graphics/Ugliceea.png" cell="4" w="1" h="2" duration="1" /> <Frame tileSet="plants/graphics/Ugliceea.png" cell="4" duration="1" />
</State> </State>
</Sprite> </Sprite>
<SpriteRenderer /> <SpriteRenderer />

View File

@ -3,9 +3,10 @@
<GameObject name="Ugliceea seed"> <GameObject name="Ugliceea seed">
<Transform /> <Transform />
<Sprite name="Ugliceea seed" anchorX="0" anchorY="1"> <Sprite w="1" h="1"
anchorX="0" anchorY="1">
<State name="0"> <State name="0">
<Frame tileSet="plants/graphics/Ugliceea.png" cell="5" w="1" h="1" duration="1" /> <Frame tileSet="plants/graphics/Ugliceea.png" cell="5" duration="1" />
</State> </State>
</Sprite> </Sprite>
<SpriteRenderer /> <SpriteRenderer />

View File

@ -1,41 +1,41 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<Sprite name="Player" <Sprite w="1" h="2"
anchorX="0.5" anchorY="0.95"> anchorX="0.5" anchorY="0.95">
<State name="Idle right"> <State name="Idle right">
<Frame tileSet="tilesets/PlayerTiles.png" cell="0" w="1" h="2" duration="1" /> <Frame tileSet="tilesets/PlayerTiles.png" cell="0" duration="1" />
</State> </State>
<State name="Idle up"> <State name="Idle up">
<Frame tileSet="tilesets/PlayerTiles.png" cell="2" w="1" h="2" duration="1" /> <Frame tileSet="tilesets/PlayerTiles.png" cell="2" duration="1" />
</State> </State>
<State name="Idle left"> <State name="Idle left">
<Frame tileSet="tilesets/PlayerTiles.png" cell="4" w="1" h="2" duration="1" /> <Frame tileSet="tilesets/PlayerTiles.png" cell="4" duration="1" />
</State> </State>
<State name="Idle down"> <State name="Idle down">
<Frame tileSet="tilesets/PlayerTiles.png" cell="6" w="1" h="2" duration="1" /> <Frame tileSet="tilesets/PlayerTiles.png" cell="6" duration="1" />
</State> </State>
<State name="Walking right"> <State name="Walking right">
<Frame tileSet="tilesets/PlayerTiles.png" cell="0" w="1" h="2" duration="0.2" /> <Frame tileSet="tilesets/PlayerTiles.png" cell="1" duration="0.2" />
<Frame tileSet="tilesets/PlayerTiles.png" cell="1" w="1" h="2" duration="0.2" /> <Frame tileSet="tilesets/PlayerTiles.png" cell="0" duration="0.2" />
</State> </State>
<State name="Walking up"> <State name="Walking up">
<Frame tileSet="tilesets/PlayerTiles.png" cell="2" w="1" h="2" duration="0.2" /> <Frame tileSet="tilesets/PlayerTiles.png" cell="3" duration="0.2" />
<Frame tileSet="tilesets/PlayerTiles.png" cell="3" w="1" h="2" duration="0.2" /> <Frame tileSet="tilesets/PlayerTiles.png" cell="2" duration="0.2" />
</State> </State>
<State name="Walking left"> <State name="Walking left">
<Frame tileSet="tilesets/PlayerTiles.png" cell="4" w="1" h="2" duration="0.2" /> <Frame tileSet="tilesets/PlayerTiles.png" cell="5" duration="0.2" />
<Frame tileSet="tilesets/PlayerTiles.png" cell="5" w="1" h="2" duration="0.2" /> <Frame tileSet="tilesets/PlayerTiles.png" cell="4" duration="0.2" />
</State> </State>
<State name="Walking down"> <State name="Walking down">
<Frame tileSet="tilesets/PlayerTiles.png" cell="6" w="1" h="2" duration="0.2" /> <Frame tileSet="tilesets/PlayerTiles.png" cell="7" duration="0.2" />
<Frame tileSet="tilesets/PlayerTiles.png" cell="7" w="1" h="2" duration="0.2" /> <Frame tileSet="tilesets/PlayerTiles.png" cell="6" duration="0.2" />
</State> </State>
</Sprite> </Sprite>

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<Sprite name="StoneHoe" <Sprite w="1" h="1"
anchorX="0" anchorY="0.1"> anchorX="0" anchorY="0.1">
<State name="Normal"> <State name="Normal">
<Frame tileSet="sprites/items/hoe.png" cell="0" w="1" h="1" duration="1" /> <Frame tileSet="sprites/items/hoe.png" cell="0" duration="1" />
</State> </State>
<State name="Attack"> <State name="Attack">
<Frame tileSet="sprites/items/hoe.png" cell="1" w="1" h="1" duration="1" /> <Frame tileSet="sprites/items/hoe.png" cell="1" duration="1" />
</State> </State>
</Sprite> </Sprite>

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<Sprite name="Lvl1Sword" <Sprite w="1" h="1"
anchorX="0" anchorY="1"> anchorX="0" anchorY="1">
<State name="Normal"> <State name="Normal">
<Frame tileSet="sprites/items/sword.png" cell="0" w="1" h="1" duration="1" /> <Frame tileSet="sprites/items/sword.png" cell="0" duration="1" />
</State> </State>
<State name="Attack"> <State name="Attack">
<Frame tileSet="sprites/items/sword.png" cell="1" w="1" h="1" duration="1" /> <Frame tileSet="sprites/items/sword.png" cell="1" duration="1" />
</State> </State>
</Sprite> </Sprite>

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<Sprite name="Lvl2Sword" <Sprite w="1" h="1"
anchorX="0" anchorY="1"> anchorX="0" anchorY="1">
<State name="Normal"> <State name="Normal">
<Frame tileSet="sprites/items/sword.png" cell="0" w="1" h="1" duration="1" /> <Frame tileSet="sprites/items/sword.png" cell="0" duration="1" />
</State> </State>
<State name="Attack"> <State name="Attack">
<Frame tileSet="sprites/items/sword.png" cell="1" w="1" h="1" duration="1" /> <Frame tileSet="sprites/items/sword.png" cell="1" duration="1" />
</State> </State>
</Sprite> </Sprite>

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<Sprite name="RustyWateringCan" <Sprite w="1" h="1"
anchorX="0" anchorY="1"> anchorX="0" anchorY="1">
<State name="Normal"> <State name="Normal">
<Frame tileSet="sprites/items/wateringCan.png" cell="0" w="1" h="1" duration="1" /> <Frame tileSet="sprites/items/wateringCan.png" cell="0" duration="1" />
</State> </State>
<State name="Attack"> <State name="Attack">
<Frame tileSet="sprites/items/wateringCan.png" cell="1" w="1" h="1" duration="1" /> <Frame tileSet="sprites/items/wateringCan.png" cell="1" duration="1" />
</State> </State>
</Sprite> </Sprite>

View File

@ -60,17 +60,14 @@ void Grid::onInitialize()
GameObject* obj = *it; GameObject* obj = *it;
// Compute grid position(s) // Compute grid position(s)
Rect<int> bounds(obj->transform.x, obj->transform.y, roundf(obj->transform.w), roundf(obj->transform.h)); if (!m_bounds.contains(obj->transform.x, obj->transform.y))
if (!bounds.intersects(m_bounds))
{ {
std::cerr << "Grid: ignoring object " << obj->name << ": object outside allowed bounds."; std::cerr << "Grid: ignoring object " << obj->name << ": object outside allowed bounds.";
continue; continue;
} }
// Set // Set
for (int y = bounds.y; y < bounds.y + bounds.h; y++) set(obj, (int)obj->transform.x, (int)obj->transform.y, false);
for (int x = bounds.x; x < bounds.x + bounds.w; x++)
set(obj, x, y, false);
} }
} }

View File

@ -17,12 +17,12 @@ namespace components {
namespace basic { namespace basic {
Sprite::Sprite() Sprite::Sprite()
: name(), : w(1), h(1),
anchorX(0), anchorY(0), anchorX(0), anchorY(0),
animationVelocity(1.0f), animationSpeed(1.0f),
m_states(), m_states(),
m_stateNames(), m_stateNames(),
m_currentState(0), m_currentState((size_t)-1),
m_currentFrame(0), m_currentFrame(0),
m_currentFrameTimeLeft(0) m_currentFrameTimeLeft(0)
{ {
@ -37,12 +37,13 @@ model::Component* Sprite::clone()
Sprite* clone = new Sprite(); Sprite* clone = new Sprite();
// Copy public fields // Copy public fields
clone->name = name; clone->w = w;
clone->h = h;
clone->anchorX = anchorX; clone->anchorX = anchorX;
clone->anchorY = anchorY; clone->anchorY = anchorY;
clone->animationVelocity = animationVelocity; clone->animationSpeed = animationSpeed;
// Copy private memberes // Copy private members
std::copy(m_states.begin(), m_states.end(), std::back_inserter(clone->m_states)); std::copy(m_states.begin(), m_states.end(), std::back_inserter(clone->m_states));
std::copy(m_stateNames.begin(), m_stateNames.end(), std::inserter(clone->m_stateNames, clone->m_stateNames.end())); std::copy(m_stateNames.begin(), m_stateNames.end(), std::inserter(clone->m_stateNames, clone->m_stateNames.end()));
clone->m_currentState = m_currentState; clone->m_currentState = m_currentState;
@ -58,7 +59,7 @@ void Sprite::dump(unsigned level)
std::cout<<" "; std::cout<<" ";
std::cout << " .Component: Sprite "; std::cout << " .Component: Sprite ";
std::cout << "name="<<name<<"\n"; std::cout << "state="<<m_currentState<<"\n";
} }
void Sprite::onPreRender() void Sprite::onPreRender()
@ -66,33 +67,69 @@ void Sprite::onPreRender()
advanceTime(GameState::current().deltaTime); advanceTime(GameState::current().deltaTime);
} }
utils::RectF Sprite::boundaries() const
{
const float sX = gameObject->transform.globalScaleX();
const float sY = gameObject->transform.globalScaleY();
return utils::RectF(
gameObject->transform.globalX() - sX * anchorX * w,
gameObject->transform.globalY() - sY * anchorY * h,
sX * w, sY * h);
}
void Sprite::addState(const SpriteState& state) void Sprite::addState(const SpriteState& state)
{ {
Assert(state.frames.size() > 0, "State must have at least one frame!"); Assert(m_stateNames.count(state.name) == 0, "A state with the same name already exists!");
#ifdef BUILD_DEBUG
float totalDuration = 0;
for (auto frame : state.frames)
totalDuration += frame.duration;
Assert(totalDuration > 0, "State must have a frame which last at least one tick.");
#endif
Assert(m_stateNames.count(state.name) == 0, "A state with the same name already added!");
m_states.push_back(state); m_states.push_back(state);
m_stateNames.emplace(state.name, m_states.size() - 1); m_stateNames.emplace(state.name, m_states.size() - 1);
// First added state?
if (m_states.size() == 1)
{
m_currentState = 0;
}
}
SpriteState& Sprite::createState(const std::string& name)
{
SpriteState state = { .name = name };
addState(state);
return m_states.back();
}
SpriteState& Sprite::state(const std::string& name)
{
Assert(m_stateNames.count(name) != 0, "State doesn't exist.");
size_t index = m_stateNames.at(name);
return m_states.at(index);
}
SpriteState& Sprite::state(size_t stateId)
{
Assert(stateId < m_states.size(), "State ID doesn't exist.");
return m_states.at(stateId);
}
size_t Sprite::stateCount() const
{
return m_states.size();
} }
void Sprite::setState(size_t stateId) void Sprite::setState(size_t stateId)
{ {
Assert(stateId < m_states.size(), "Inexistent state."); Assert(stateId < m_states.size(), "Inexistent state.");
// Avoid resetting state // Avoid restarting the animation at every function call
if (stateId == m_currentState) if (stateId != m_currentState)
return; {
m_currentState = stateId;
m_currentState = stateId; m_currentFrame = 0;
m_currentFrame = 0; m_currentFrameTimeLeft = currentFrame().duration;
m_currentFrameTimeLeft = currentFrame().duration; }
} }
void Sprite::setState(const std::string& name) void Sprite::setState(const std::string& name)
@ -103,21 +140,22 @@ void Sprite::setState(const std::string& name)
SpriteState& Sprite::currentState() SpriteState& Sprite::currentState()
{ {
Assert(m_currentState != (size_t)-1, "No states have been added!!!");
Assert(m_states.size() > 0, "Sprite must have at least one state!"); Assert(m_states.size() > 0, "Sprite must have at least one state!");
return m_states.at(m_currentState); return m_states.at(m_currentState);
} }
Frame& Sprite::currentFrame() Frame& Sprite::currentFrame()
{ {
Assert(currentState().frames.size() > 0, "State must have at least one frame!"); Assert(m_currentFrame < currentState().frames.size(), "State must have at least one frame!");
return currentState().frames.at(m_currentFrame); return currentState().frames.at(m_currentFrame);
} }
void Sprite::advanceTime(float fractions) void Sprite::advanceTime(float fractions)
{ {
Assert(m_states.size() > 0, "Sprite must have at least one state!"); Assert(m_currentState != (size_t)-1, "No states have been added!");
m_currentFrameTimeLeft -= fractions * animationVelocity; m_currentFrameTimeLeft -= fractions * animationSpeed;
while (m_currentFrameTimeLeft <= 0) while (m_currentFrameTimeLeft <= 0)
{ {

View File

@ -10,6 +10,7 @@
#include <model/Component.h> #include <model/Component.h>
#include <utils/Exceptions.h> #include <utils/Exceptions.h>
#include <utils/Rect.h>
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
@ -25,7 +26,6 @@ namespace basic {
{ {
uint32_t tileSetId; uint32_t tileSetId;
uint32_t tileSetCell; uint32_t tileSetCell;
uint32_t width, height;
float duration; float duration;
}; };
@ -53,28 +53,31 @@ namespace basic {
virtual void onPreRender() override; virtual void onPreRender() override;
/** /**
* Adds a state to the sprite. * Computes the boundaries of the sprite, considering all the elements:
* - global coordinates and scale
* - width and height
* - anchor point
*/ */
utils::RectF boundaries() const;
// State management
void addState(const SpriteState& state); void addState(const SpriteState& state);
SpriteState& createState(const std::string& name);
SpriteState& state(const std::string& name);
SpriteState& state(size_t stateId);
size_t stateCount() const;
/** // Current state & frame
* Sets the current state.
*/
void setState(size_t stateId); void setState(size_t stateId);
/**
* Sets the current state.
*/
void setState(const std::string& name); void setState(const std::string& name);
// Getters
SpriteState& currentState(); SpriteState& currentState();
Frame& currentFrame(); Frame& currentFrame();
// Public fields // Public fields
std::string name; float w, h;
float anchorX, anchorY; float anchorX, anchorY;
float animationVelocity;
float animationSpeed;
private: private:
void advanceTime(float fractions); void advanceTime(float fractions);

View File

@ -27,24 +27,12 @@ static const float PlayerWalkVelocity = 2.0f; // The default velocity of the p
static const float PlayerRunVelocity = 4.0f; // The default velocity of the player when running (units/sec). static const float PlayerRunVelocity = 4.0f; // The default velocity of the player when running (units/sec).
static const float PlayerAttackVelocity = 0.1f; // Movement speed when attacking. static const float PlayerAttackVelocity = 0.1f; // Movement speed when attacking.
static const float PickablePickTreshold = 0.7f;
/** /**
* Distance from player position to "look" position. * Distance from player position to "look" position.
* This position is used for picking the cell which will be affected by the player's actions. * This position is used for picking the cell which will be affected by the player's actions.
*/ */
static const float PlayerLookDistance = 0.5f; static const float PlayerLookDistance = 0.5f;
/**
* Map between velocity and direction.
*/
static const Direction VelocitySignDirections[3][3] =
{
{ Direction::NorthWest, Direction::West, Direction::SouthWest },
{ Direction::North, Direction::None, Direction::South },
{ Direction::NorthEast, Direction::East, Direction::SouthEast },
};
Player::Player() Player::Player()
: selectedItemIndex(-1), : selectedItemIndex(-1),
selectedItem(nullptr), selectedItem(nullptr),
@ -183,8 +171,9 @@ void Player::handleInventoryDropEvent(SDL_Event& event)
selectedItem->addComponent(new Pickable()); selectedItem->addComponent(new Pickable());
// Set location // Set location
translate(gameObject->transform.x, gameObject->transform.y, facingDirection, 2.0f, selectedItem->transform.x = gameObject->transform.x;
&selectedItem->transform.x, &selectedItem->transform.y); selectedItem->transform.y = gameObject->transform.y;
move(&selectedItem->transform.x, &selectedItem->transform.y, facingDirection, 2.0f);
// Remove selection // Remove selection
selectedItemIndex = -1; selectedItemIndex = -1;
@ -231,12 +220,12 @@ void Player::preRenderSelectedItem()
// Set item position // Set item position
if (selectedItem) if (selectedItem)
{ {
if (facingDirection & Direction::East) if (facingDirection == Direction::East)
{ {
selectedItem->transform.x = 0.2f; selectedItem->transform.x = 0.2f;
selectedItem->transform.y = -0.8f; selectedItem->transform.y = -0.8f;
} }
else if (facingDirection & Direction::West) else if (facingDirection == Direction::West)
{ {
selectedItem->transform.x = -0.8f; selectedItem->transform.x = -0.8f;
selectedItem->transform.y = -0.8f; selectedItem->transform.y = -0.8f;
@ -252,14 +241,21 @@ void Player::preRenderMovement()
// Compute current state // Compute current state
std::string stateName = (walking) ? "Walking " : "Idle "; std::string stateName = (walking) ? "Walking " : "Idle ";
if (facingDirection & Direction::East) switch (facingDirection)
{
case Direction::East:
stateName += "right"; stateName += "right";
else if (facingDirection & Direction::West) break;
case Direction::West:
stateName += "left"; stateName += "left";
else if (facingDirection & Direction::North) break;
case Direction::North:
stateName += "up"; stateName += "up";
else break;
case Direction::South:
stateName += "down"; stateName += "down";
break;
}
sprite->setState(stateName); sprite->setState(stateName);
@ -269,7 +265,7 @@ void Player::preRenderMovement()
animVelocity = 0.1f; animVelocity = 0.1f;
// TODO: move this animation velocity change somewhere else // TODO: move this animation velocity change somewhere else
sprite->animationVelocity = animVelocity; sprite->animationSpeed = animVelocity;
// Set camera // Set camera
GameObject* cam = GameState::current().renderContext.cameraObj(); GameObject* cam = GameState::current().renderContext.cameraObj();
@ -306,16 +302,17 @@ void Player::updateMovement()
walking = true; walking = true;
facingDirection = getDirection(vx, vy); facingDirection = getDirection(vx, vy);
translate(newX, newY, facingDirection, PlayerLookDistance, &lookX, &lookY); lookX = newX;
lookY = newY;
move(&lookX, &lookY, facingDirection, PlayerLookDistance);
} }
} }
Direction Player::getDirection(float vx, float vy) Direction Player::getDirection(float vx, float vy)
{ {
int xx = (0 < vx) - (vx < 0); if (vx != 0)
int yy = (0 < vy) - (vy < 0); return (vx > 0) ? Direction::East : Direction::West;
return (vy > 0) ? Direction::South : Direction::North;
return VelocitySignDirections[xx + 1][yy + 1];
} }
void Player::handleActionEvents(SDL_Event& event) void Player::handleActionEvents(SDL_Event& event)
@ -374,15 +371,14 @@ void Player::updatePickables()
if (pickable) if (pickable)
{ {
// Compute distance from player if (checkCollision(gameObject, obj))
float dist = distanceSq(gameObject->transform.x, gameObject->transform.y, obj->transform.x, obj->transform.y);
// Pick the object up
if (dist < PickablePickTreshold * PickablePickTreshold)
{ {
// We can't modify the container now, so queue the item for picking up // We can't modify the container now, so queue the item for picking up
toPickUp.push_back(obj); toPickUp.push_back(obj);
} }
// Compute distance from player
// float dist = distanceSq(gameObject->transform.x, gameObject->transform.y, obj->transform.x, obj->transform.y);
} }
} }

View File

@ -44,20 +44,20 @@ void SpriteRenderer::onInitialize()
void SpriteRenderer::onRender() void SpriteRenderer::onRender()
{ {
float posX = m_context->xToScreen(gameObject->transform.globalX()); utils::RectF bounds = m_sprite->boundaries();
float posY = m_context->yToScreen(gameObject->transform.globalY()); float spriteW = bounds.w * m_context->viewport.pixelsPerUnitX;
float spriteH = bounds.h * m_context->viewport.pixelsPerUnitY;
float w = m_sprite->currentFrame().width * m_context->viewport.pixelsPerUnitX;
float h = m_sprite->currentFrame().height * m_context->viewport.pixelsPerUnitY;
// Compute destination rectangle // Compute destination rectangle
float scale = m_context->camera()->scale; float scale = m_context->camera()->scale;
SDL_Rect dest; SDL_Rect dest =
dest.x = posX - m_sprite->anchorX * w * scale; {
dest.y = posY - m_sprite->anchorY * h * scale; .x = static_cast<int>(m_context->xToScreen(bounds.x)),
dest.w = w * scale; .y = static_cast<int>(m_context->yToScreen(bounds.y)),
dest.h = h * scale; .w = static_cast<int>(spriteW * scale),
.h = static_cast<int>(spriteH * scale)
};
if (m_context->visible(dest)) if (m_context->visible(dest))
{ {
@ -68,8 +68,8 @@ void SpriteRenderer::onRender()
// Compute source rectangle // Compute source rectangle
SDL_Rect src; SDL_Rect src;
getCell(texture, m_sprite->currentFrame().tileSetCell, &src.x, &src.y); getCell(texture, m_sprite->currentFrame().tileSetCell, &src.x, &src.y);
src.w = w; src.w = spriteW;
src.h = h; src.h = spriteH;
// Draw // Draw
SdlRenderer::instance().renderTexture(texture, &src, &dest); SdlRenderer::instance().renderTexture(texture, &src, &dest);

View File

@ -5,36 +5,23 @@
* Author: tibi * Author: tibi
*/ */
#include <components/basic/Sprite.h>
#include <math/GameMath.h> #include <math/GameMath.h>
#include <model/Transform.h>
#include <utils/Rect.h>
#include <cmath> #include <cmath>
using namespace farmlands::components::basic;
namespace farmlands { namespace farmlands {
static const float Sqrt2 = 1.41421356237309504880f; void move(float *x, float *y, model::Direction direction, float distance)
static const float DirectionVectorX[] =
{ {
0, 1, 0, Sqrt2, // none, E, N, NE float dx = cosf(degToRad(direction));
-1, 0, -Sqrt2, 0, // W, inv, NW, inv float dy = sinf(degToRad(direction));
0, Sqrt2, 0, 0, // S, SE, inv, inv
-Sqrt2, 0, 0, 0 // SW, inv, inv, inv
};
static const float DirectionVectorY[] = *x += dx * distance;
{ *x += dy * distance;
0, 0, -1, -Sqrt2, // none, E, N, NE
0, 0, -Sqrt2, 0, // W, inv, NW, inv
1, Sqrt2, 0, 0, // S, SE, inv, inv
Sqrt2, 0, 0, 0 // SW, inv, inv, inv
};
void translate(float x, float y, model::Direction direction, float distance, float* outX, float *outY)
{
float dx = DirectionVectorX[direction];
float dy = DirectionVectorY[direction];
*outX = x + dx * distance;
*outY = y + dy * distance;
} }
void moveTowards(float *x, float *y, float towardsX, float towardsY, float speed) void moveTowards(float *x, float *y, float towardsX, float towardsY, float speed)
@ -49,4 +36,24 @@ float distanceSq(float x0, float y0, float x1, float y1)
return (x0 - x1) * (x0 - x1) + (y0 - y1) * (y0 - y1); return (x0 - x1) * (x0 - x1) + (y0 - y1) * (y0 - y1);
} }
bool checkCollision(model::GameObject* objA, model::GameObject* objB)
{
Sprite* sprA = objA->component<Sprite>();
Sprite* sprB = objB->component<Sprite>();
// If both have sprites, they intersect if their rectangles intersect
if (sprA && sprB)
return sprA->boundaries().intersects(sprB->boundaries());
// Only one has sprite. They collide if sprite rectangle contains the other point
if (sprA)
return sprA->boundaries().contains(objB->transform.globalX(), objB->transform.globalY());
if (sprB)
return sprB->boundaries().contains(objA->transform.globalX(), objA->transform.globalY());
// Objects collide if their coordinates are equal.
return std::abs(objA->transform.globalX() - objB->transform.globalX()) < 1e-10
&& std::abs(objA->transform.globalY() - objB->transform.globalY()) < 1e-10;
}
} }

View File

@ -9,9 +9,20 @@
#define MATH_GAMEMATH_H_ #define MATH_GAMEMATH_H_
#include <model/Direction.h> #include <model/Direction.h>
#include <model/GameObject.h>
#define _USE_MATH_DEFINES
#include <cmath>
namespace farmlands { namespace farmlands {
void move(float* x, float* y, model::Direction direction, float distance);
void moveTowards(float *x, float *y, float towardsX, float towardsY, float speed);
float distanceSq(float x0, float y0, float x1, float y1);
bool checkCollision(model::GameObject* objA, model::GameObject* objB);
template<typename TVal, typename TMin, typename TMax> template<typename TVal, typename TMin, typename TMax>
TVal clamp (TVal value, TMin min, TMax max) TVal clamp (TVal value, TMin min, TMax max)
{ {
@ -24,9 +35,12 @@ namespace farmlands {
return value; return value;
} }
void translate(float x, float y, model::Direction direction, float distance, float* outX, float* outY); /**
void moveTowards(float *x, float *y, float towardsX, float towardsY, float speed); * Converts from degrees to radians
float distanceSq(float x0, float y0, float x1, float y1); */
inline float degToRad(float angle)
{
return angle * (float)M_PI / 360.0f;
}
} }
#endif /* MATH_GAMEMATH_H_ */ #endif /* MATH_GAMEMATH_H_ */

View File

@ -14,14 +14,10 @@ namespace model {
enum Direction enum Direction
{ {
None = 0, None = 0,
East = 1, East = 0,
North = 2, North = 90,
West = 4, West = 180,
South = 8, South = 270
NorthEast = North | East,
NorthWest = North | West,
SouthWest = South | West,
SouthEast = South | East
}; };
} }

View File

@ -8,7 +8,7 @@
#include <GameState.h> #include <GameState.h>
#include <model/GameObject.h> #include <model/GameObject.h>
#include <model/Component.h> #include <model/Component.h>
#include <model/Transform.h>
#include <iostream> #include <iostream>
namespace farmlands { namespace farmlands {

View File

@ -1,58 +1,71 @@
/*
* Transform.cpp
*
* Created on: Dec 2, 2016
* Author: tibi
*/
#include <model/GameObject.h> #include <model/GameObject.h>
#include <model/Transform.h> #include <model/Transform.h>
#include <iostream>
namespace farmlands { namespace farmlands {
namespace model { namespace model {
Transform::Transform(GameObject* obj) Transform::Transform(GameObject* obj)
: x(0), y(0), : x(0), y(0),
w(0), h(0), scaleX(1), scaleY(1),
gameObject(obj) gameObject(obj)
{ {
} }
float Transform::globalX() const float Transform::globalX() const
{ {
if (gameObject->parent()) return (gameObject->parent())
return gameObject->parent()->transform.globalX() + x; ? x + gameObject->parent()->transform.globalX()
: x;
return x;
} }
float Transform::globalY() const float Transform::globalY() const
{ {
if (gameObject->parent()) return (gameObject->parent())
return gameObject->parent()->transform.globalY() + y; ? y + gameObject->parent()->transform.globalY()
: y;
return y;
} }
void Transform::setGlobalX(float x) void Transform::setGlobalX(float gx)
{ {
if (gameObject->parent()) x = (gameObject->parent())
this->x = x - gameObject->parent()->transform.globalX(); ? gx - gameObject->parent()->transform.globalX()
: gx;
this->x = x;
} }
void Transform::setGlobalY(float y) void Transform::setGlobalY(float gy)
{ {
if (gameObject->parent()) y = (gameObject->parent())
this->y = y - gameObject->parent()->transform.globalY(); ? gy - gameObject->parent()->transform.globalY()
: gy;
}
this->y = y; float Transform::globalScaleX() const
{
return (gameObject->parent())
? scaleX * gameObject->parent()->transform.globalScaleX()
: scaleX;
}
float Transform::globalScaleY() const
{
return (gameObject->parent())
? scaleY * gameObject->parent()->transform.globalScaleY()
: scaleY;
}
void Transform::setGlobalScaleX(float gscaleX)
{
scaleX = (gameObject->parent())
? gscaleX / gameObject->parent()->transform.globalScaleX()
: gscaleX;
}
void Transform::setGlobalScaleY(float gscaleY)
{
scaleY = (gameObject->parent())
? gscaleY / gameObject->parent()->transform.globalScaleY()
: gscaleY;
} }
} }
} /* namespace farmlands */ } /* namespace farmlands */

View File

@ -21,15 +21,20 @@ namespace model {
// Getters // Getters
float globalX() const; float globalX() const;
float globalY() const; float globalY() const;
float globalScaleX() const;
float globalScaleY() const;
// Setters // Setters
void setGlobalX(float x); void setGlobalX(float gx);
void setGlobalY(float y); void setGlobalY(float gy);
void setGlobalScaleX(float gscaleX);
void setGlobalScaleY(float gscaleY);
// Local coordinates (relative to parent) // Local coordinates (relative to parent)
float x, y; float x, y;
float w, h; float scaleX, scaleY;
// Parent object
GameObject* gameObject; GameObject* gameObject;
}; };

View File

@ -123,14 +123,10 @@ components::basic::Frame* parse<components::basic::Frame> (boost::property_tree:
components::basic::Frame* frame = new components::basic::Frame(); components::basic::Frame* frame = new components::basic::Frame();
// Obtine tile set id // Set properties
std::string tileSetPath = root.get<std::string>("<xmlattr>.tileSet"); std::string tileSetPath = root.get<std::string>("<xmlattr>.tileSet");
frame->tileSetId = resources::ResourceManager::instance().getId(tileSetPath); frame->tileSetId = resources::ResourceManager::instance().getId(tileSetPath);
// Set properties
frame->tileSetCell = root.get<int>("<xmlattr>.cell"); frame->tileSetCell = root.get<int>("<xmlattr>.cell");
frame->width = root.get<uint32_t>("<xmlattr>.w", 1u);
frame->height = root.get<uint32_t>("<xmlattr>.h", 1u);
frame->duration = root.get<float>("<xmlattr>.duration"); frame->duration = root.get<float>("<xmlattr>.duration");
return frame; return frame;
@ -202,9 +198,11 @@ components::basic::Sprite* parse<components::basic::Sprite> (boost::property_tre
// Parse components::basic::Sprite // Parse components::basic::Sprite
components::basic::Sprite* sprite = new components::basic::Sprite(); components::basic::Sprite* sprite = new components::basic::Sprite();
sprite->w = root.get<float>("<xmlattr>.w");
sprite->h = root.get<float>("<xmlattr>.h");
sprite->anchorX = root.get<float>("<xmlattr>.anchorX"); sprite->anchorX = root.get<float>("<xmlattr>.anchorX");
sprite->anchorY = root.get<float>("<xmlattr>.anchorY"); sprite->anchorY = root.get<float>("<xmlattr>.anchorY");
sprite->animationVelocity = root.get<float>("<xmlattr>.animationVelocity", 1.0f); sprite->animationSpeed = root.get<float>("<xmlattr>.animationSpeed", 1.0f);
for (auto child : root) for (auto child : root)
{ {
@ -451,14 +449,14 @@ model::Direction parseDirection(std::string directionStr)
model::Direction direction = model::Direction::None; model::Direction direction = model::Direction::None;
boost::to_lower(directionStr); boost::to_lower(directionStr);
if (boost::contains(directionStr, "east")) if (directionStr == "east")
direction = (model::Direction) (direction | model::Direction::East); direction = model::Direction::East;
if (boost::contains(directionStr, "north")) if (directionStr == "north")
direction = (model::Direction) (direction | model::Direction::North); direction = model::Direction::North;
if (boost::contains(directionStr, "west")) if (directionStr == "west")
direction = (model::Direction) (direction | model::Direction::West); direction = model::Direction::West;
if (boost::contains(directionStr, "south")) if (directionStr == "south")
direction = (model::Direction) (direction | model::Direction::South); direction = model::Direction::South;
return direction; return direction;
} }
@ -533,8 +531,8 @@ void parseTransform (model::Transform& transform, boost::property_tree::ptree& r
transform.x = root.get<float>("<xmlattr>.x", 0.0f); transform.x = root.get<float>("<xmlattr>.x", 0.0f);
transform.y = root.get<float>("<xmlattr>.y", 0.0f); transform.y = root.get<float>("<xmlattr>.y", 0.0f);
transform.w = root.get<float>("<xmlattr>.w", 1.0f); transform.scaleX = root.get<float>("<xmlattr>.scaleX", 1.0f);
transform.h = root.get<float>("<xmlattr>.h", 1.0f); transform.scaleY = root.get<float>("<xmlattr>.scaleY", 1.0f);
} }
template <> template <>