Refactored sprite & transform. Replaced distance with collider when picking objects up.
This commit is contained in:
parent
ddae4934ef
commit
42f0d4125b
@ -29,7 +29,6 @@
|
||||
</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">
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Farmlands/src}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Farmlands/import/include}""/>
|
||||
</option>
|
||||
<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1411957018" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
|
||||
</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.include.paths.1506817800" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths" useByScannerDiscovery="false" valueType="includePath">
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Farmlands/src}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Farmlands/import/include}""/>
|
||||
</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">
|
||||
<listOptionValue builtIn="false" value="BUILD_DEBUG"/>
|
||||
@ -105,7 +103,6 @@
|
||||
</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">
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Farmlands/src}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Farmlands/import/include}""/>
|
||||
</option>
|
||||
<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1719824945" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
|
||||
</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.include.paths.1574426438" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths" useByScannerDiscovery="false" valueType="includePath">
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Farmlands/src}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Farmlands/import/include}""/>
|
||||
</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">
|
||||
<listOptionValue builtIn="false" value="BUILD_RELEASE"/>
|
||||
|
@ -3,21 +3,22 @@
|
||||
|
||||
<GameObject name="Ugliceea">
|
||||
<Transform />
|
||||
<Sprite name="Ugliceea" anchorX="0" anchorY=".5">
|
||||
<Sprite w="1" h="2"
|
||||
anchorX="0" anchorY=".5">
|
||||
<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 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 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 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 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>
|
||||
</Sprite>
|
||||
<SpriteRenderer />
|
||||
|
@ -3,9 +3,10 @@
|
||||
|
||||
<GameObject name="Ugliceea seed">
|
||||
<Transform />
|
||||
<Sprite name="Ugliceea seed" anchorX="0" anchorY="1">
|
||||
<Sprite w="1" h="1"
|
||||
anchorX="0" anchorY="1">
|
||||
<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>
|
||||
</Sprite>
|
||||
<SpriteRenderer />
|
||||
|
@ -1,41 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Sprite name="Player"
|
||||
<Sprite w="1" h="2"
|
||||
anchorX="0.5" anchorY="0.95">
|
||||
|
||||
<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 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 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 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 name="Walking right">
|
||||
<Frame tileSet="tilesets/PlayerTiles.png" cell="0" w="1" h="2" duration="0.2" />
|
||||
<Frame tileSet="tilesets/PlayerTiles.png" cell="1" w="1" h="2" duration="0.2" />
|
||||
<Frame tileSet="tilesets/PlayerTiles.png" cell="1" duration="0.2" />
|
||||
<Frame tileSet="tilesets/PlayerTiles.png" cell="0" duration="0.2" />
|
||||
</State>
|
||||
|
||||
<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" w="1" h="2" duration="0.2" />
|
||||
<Frame tileSet="tilesets/PlayerTiles.png" cell="3" duration="0.2" />
|
||||
<Frame tileSet="tilesets/PlayerTiles.png" cell="2" duration="0.2" />
|
||||
</State>
|
||||
|
||||
<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" w="1" h="2" duration="0.2" />
|
||||
<Frame tileSet="tilesets/PlayerTiles.png" cell="5" duration="0.2" />
|
||||
<Frame tileSet="tilesets/PlayerTiles.png" cell="4" duration="0.2" />
|
||||
</State>
|
||||
|
||||
<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" w="1" h="2" duration="0.2" />
|
||||
<Frame tileSet="tilesets/PlayerTiles.png" cell="7" duration="0.2" />
|
||||
<Frame tileSet="tilesets/PlayerTiles.png" cell="6" duration="0.2" />
|
||||
</State>
|
||||
|
||||
</Sprite>
|
@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Sprite name="StoneHoe"
|
||||
<Sprite w="1" h="1"
|
||||
anchorX="0" anchorY="0.1">
|
||||
<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 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>
|
||||
</Sprite>
|
@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Sprite name="Lvl1Sword"
|
||||
<Sprite w="1" h="1"
|
||||
anchorX="0" anchorY="1">
|
||||
<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 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>
|
||||
</Sprite>
|
@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Sprite name="Lvl2Sword"
|
||||
<Sprite w="1" h="1"
|
||||
anchorX="0" anchorY="1">
|
||||
<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 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>
|
||||
</Sprite>
|
@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Sprite name="RustyWateringCan"
|
||||
<Sprite w="1" h="1"
|
||||
anchorX="0" anchorY="1">
|
||||
<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 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>
|
||||
</Sprite>
|
@ -60,17 +60,14 @@ void Grid::onInitialize()
|
||||
GameObject* obj = *it;
|
||||
|
||||
// Compute grid position(s)
|
||||
Rect<int> bounds(obj->transform.x, obj->transform.y, roundf(obj->transform.w), roundf(obj->transform.h));
|
||||
if (!bounds.intersects(m_bounds))
|
||||
if (!m_bounds.contains(obj->transform.x, obj->transform.y))
|
||||
{
|
||||
std::cerr << "Grid: ignoring object " << obj->name << ": object outside allowed bounds.";
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set
|
||||
for (int y = bounds.y; y < bounds.y + bounds.h; y++)
|
||||
for (int x = bounds.x; x < bounds.x + bounds.w; x++)
|
||||
set(obj, x, y, false);
|
||||
set(obj, (int)obj->transform.x, (int)obj->transform.y, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,12 +17,12 @@ namespace components {
|
||||
namespace basic {
|
||||
|
||||
Sprite::Sprite()
|
||||
: name(),
|
||||
: w(1), h(1),
|
||||
anchorX(0), anchorY(0),
|
||||
animationVelocity(1.0f),
|
||||
animationSpeed(1.0f),
|
||||
m_states(),
|
||||
m_stateNames(),
|
||||
m_currentState(0),
|
||||
m_currentState((size_t)-1),
|
||||
m_currentFrame(0),
|
||||
m_currentFrameTimeLeft(0)
|
||||
{
|
||||
@ -37,12 +37,13 @@ model::Component* Sprite::clone()
|
||||
Sprite* clone = new Sprite();
|
||||
|
||||
// Copy public fields
|
||||
clone->name = name;
|
||||
clone->w = w;
|
||||
clone->h = h;
|
||||
clone->anchorX = anchorX;
|
||||
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_stateNames.begin(), m_stateNames.end(), std::inserter(clone->m_stateNames, clone->m_stateNames.end()));
|
||||
clone->m_currentState = m_currentState;
|
||||
@ -58,7 +59,7 @@ void Sprite::dump(unsigned level)
|
||||
std::cout<<" ";
|
||||
|
||||
std::cout << " .Component: Sprite ";
|
||||
std::cout << "name="<<name<<"\n";
|
||||
std::cout << "state="<<m_currentState<<"\n";
|
||||
}
|
||||
|
||||
void Sprite::onPreRender()
|
||||
@ -66,33 +67,69 @@ void Sprite::onPreRender()
|
||||
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)
|
||||
{
|
||||
Assert(state.frames.size() > 0, "State must have at least one frame!");
|
||||
#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!");
|
||||
Assert(m_stateNames.count(state.name) == 0, "A state with the same name already exists!");
|
||||
|
||||
m_states.push_back(state);
|
||||
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)
|
||||
{
|
||||
Assert(stateId < m_states.size(), "Inexistent state.");
|
||||
|
||||
// Avoid resetting state
|
||||
if (stateId == m_currentState)
|
||||
return;
|
||||
|
||||
// Avoid restarting the animation at every function call
|
||||
if (stateId != m_currentState)
|
||||
{
|
||||
m_currentState = stateId;
|
||||
m_currentFrame = 0;
|
||||
m_currentFrameTimeLeft = currentFrame().duration;
|
||||
}
|
||||
}
|
||||
|
||||
void Sprite::setState(const std::string& name)
|
||||
@ -103,21 +140,22 @@ void Sprite::setState(const std::string& name)
|
||||
|
||||
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!");
|
||||
return m_states.at(m_currentState);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include <model/Component.h>
|
||||
#include <utils/Exceptions.h>
|
||||
#include <utils/Rect.h>
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
@ -25,7 +26,6 @@ namespace basic {
|
||||
{
|
||||
uint32_t tileSetId;
|
||||
uint32_t tileSetCell;
|
||||
uint32_t width, height;
|
||||
float duration;
|
||||
};
|
||||
|
||||
@ -53,28 +53,31 @@ namespace basic {
|
||||
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);
|
||||
SpriteState& createState(const std::string& name);
|
||||
SpriteState& state(const std::string& name);
|
||||
SpriteState& state(size_t stateId);
|
||||
size_t stateCount() const;
|
||||
|
||||
/**
|
||||
* Sets the current state.
|
||||
*/
|
||||
// Current state & frame
|
||||
void setState(size_t stateId);
|
||||
|
||||
/**
|
||||
* Sets the current state.
|
||||
*/
|
||||
void setState(const std::string& name);
|
||||
|
||||
// Getters
|
||||
SpriteState& currentState();
|
||||
Frame& currentFrame();
|
||||
|
||||
// Public fields
|
||||
std::string name;
|
||||
float w, h;
|
||||
float anchorX, anchorY;
|
||||
float animationVelocity;
|
||||
|
||||
float animationSpeed;
|
||||
|
||||
private:
|
||||
void advanceTime(float fractions);
|
||||
|
@ -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 PlayerAttackVelocity = 0.1f; // Movement speed when attacking.
|
||||
|
||||
static const float PickablePickTreshold = 0.7f;
|
||||
|
||||
/**
|
||||
* Distance from player position to "look" position.
|
||||
* This position is used for picking the cell which will be affected by the player's actions.
|
||||
*/
|
||||
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()
|
||||
: selectedItemIndex(-1),
|
||||
selectedItem(nullptr),
|
||||
@ -183,8 +171,9 @@ void Player::handleInventoryDropEvent(SDL_Event& event)
|
||||
selectedItem->addComponent(new Pickable());
|
||||
|
||||
// Set location
|
||||
translate(gameObject->transform.x, gameObject->transform.y, facingDirection, 2.0f,
|
||||
&selectedItem->transform.x, &selectedItem->transform.y);
|
||||
selectedItem->transform.x = gameObject->transform.x;
|
||||
selectedItem->transform.y = gameObject->transform.y;
|
||||
move(&selectedItem->transform.x, &selectedItem->transform.y, facingDirection, 2.0f);
|
||||
|
||||
// Remove selection
|
||||
selectedItemIndex = -1;
|
||||
@ -231,12 +220,12 @@ void Player::preRenderSelectedItem()
|
||||
// Set item position
|
||||
if (selectedItem)
|
||||
{
|
||||
if (facingDirection & Direction::East)
|
||||
if (facingDirection == Direction::East)
|
||||
{
|
||||
selectedItem->transform.x = 0.2f;
|
||||
selectedItem->transform.y = -0.8f;
|
||||
}
|
||||
else if (facingDirection & Direction::West)
|
||||
else if (facingDirection == Direction::West)
|
||||
{
|
||||
selectedItem->transform.x = -0.8f;
|
||||
selectedItem->transform.y = -0.8f;
|
||||
@ -252,14 +241,21 @@ void Player::preRenderMovement()
|
||||
// Compute current state
|
||||
std::string stateName = (walking) ? "Walking " : "Idle ";
|
||||
|
||||
if (facingDirection & Direction::East)
|
||||
switch (facingDirection)
|
||||
{
|
||||
case Direction::East:
|
||||
stateName += "right";
|
||||
else if (facingDirection & Direction::West)
|
||||
break;
|
||||
case Direction::West:
|
||||
stateName += "left";
|
||||
else if (facingDirection & Direction::North)
|
||||
break;
|
||||
case Direction::North:
|
||||
stateName += "up";
|
||||
else
|
||||
break;
|
||||
case Direction::South:
|
||||
stateName += "down";
|
||||
break;
|
||||
}
|
||||
|
||||
sprite->setState(stateName);
|
||||
|
||||
@ -269,7 +265,7 @@ void Player::preRenderMovement()
|
||||
animVelocity = 0.1f;
|
||||
// TODO: move this animation velocity change somewhere else
|
||||
|
||||
sprite->animationVelocity = animVelocity;
|
||||
sprite->animationSpeed = animVelocity;
|
||||
|
||||
// Set camera
|
||||
GameObject* cam = GameState::current().renderContext.cameraObj();
|
||||
@ -306,16 +302,17 @@ void Player::updateMovement()
|
||||
walking = true;
|
||||
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)
|
||||
{
|
||||
int xx = (0 < vx) - (vx < 0);
|
||||
int yy = (0 < vy) - (vy < 0);
|
||||
|
||||
return VelocitySignDirections[xx + 1][yy + 1];
|
||||
if (vx != 0)
|
||||
return (vx > 0) ? Direction::East : Direction::West;
|
||||
return (vy > 0) ? Direction::South : Direction::North;
|
||||
}
|
||||
|
||||
void Player::handleActionEvents(SDL_Event& event)
|
||||
@ -374,15 +371,14 @@ void Player::updatePickables()
|
||||
|
||||
if (pickable)
|
||||
{
|
||||
// Compute distance from player
|
||||
float dist = distanceSq(gameObject->transform.x, gameObject->transform.y, obj->transform.x, obj->transform.y);
|
||||
|
||||
// Pick the object up
|
||||
if (dist < PickablePickTreshold * PickablePickTreshold)
|
||||
if (checkCollision(gameObject, obj))
|
||||
{
|
||||
// We can't modify the container now, so queue the item for picking up
|
||||
toPickUp.push_back(obj);
|
||||
}
|
||||
// Compute distance from player
|
||||
// float dist = distanceSq(gameObject->transform.x, gameObject->transform.y, obj->transform.x, obj->transform.y);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,20 +44,20 @@ void SpriteRenderer::onInitialize()
|
||||
|
||||
void SpriteRenderer::onRender()
|
||||
{
|
||||
float posX = m_context->xToScreen(gameObject->transform.globalX());
|
||||
float posY = m_context->yToScreen(gameObject->transform.globalY());
|
||||
|
||||
float w = m_sprite->currentFrame().width * m_context->viewport.pixelsPerUnitX;
|
||||
float h = m_sprite->currentFrame().height * m_context->viewport.pixelsPerUnitY;
|
||||
utils::RectF bounds = m_sprite->boundaries();
|
||||
float spriteW = bounds.w * m_context->viewport.pixelsPerUnitX;
|
||||
float spriteH = bounds.h * m_context->viewport.pixelsPerUnitY;
|
||||
|
||||
// Compute destination rectangle
|
||||
float scale = m_context->camera()->scale;
|
||||
|
||||
SDL_Rect dest;
|
||||
dest.x = posX - m_sprite->anchorX * w * scale;
|
||||
dest.y = posY - m_sprite->anchorY * h * scale;
|
||||
dest.w = w * scale;
|
||||
dest.h = h * scale;
|
||||
SDL_Rect dest =
|
||||
{
|
||||
.x = static_cast<int>(m_context->xToScreen(bounds.x)),
|
||||
.y = static_cast<int>(m_context->yToScreen(bounds.y)),
|
||||
.w = static_cast<int>(spriteW * scale),
|
||||
.h = static_cast<int>(spriteH * scale)
|
||||
};
|
||||
|
||||
if (m_context->visible(dest))
|
||||
{
|
||||
@ -68,8 +68,8 @@ void SpriteRenderer::onRender()
|
||||
// Compute source rectangle
|
||||
SDL_Rect src;
|
||||
getCell(texture, m_sprite->currentFrame().tileSetCell, &src.x, &src.y);
|
||||
src.w = w;
|
||||
src.h = h;
|
||||
src.w = spriteW;
|
||||
src.h = spriteH;
|
||||
|
||||
// Draw
|
||||
SdlRenderer::instance().renderTexture(texture, &src, &dest);
|
||||
|
@ -5,36 +5,23 @@
|
||||
* Author: tibi
|
||||
*/
|
||||
|
||||
#include <components/basic/Sprite.h>
|
||||
#include <math/GameMath.h>
|
||||
#include <model/Transform.h>
|
||||
#include <utils/Rect.h>
|
||||
#include <cmath>
|
||||
|
||||
using namespace farmlands::components::basic;
|
||||
|
||||
namespace farmlands {
|
||||
|
||||
static const float Sqrt2 = 1.41421356237309504880f;
|
||||
|
||||
static const float DirectionVectorX[] =
|
||||
void move(float *x, float *y, model::Direction direction, float distance)
|
||||
{
|
||||
0, 1, 0, Sqrt2, // none, E, N, NE
|
||||
-1, 0, -Sqrt2, 0, // W, inv, NW, inv
|
||||
0, Sqrt2, 0, 0, // S, SE, inv, inv
|
||||
-Sqrt2, 0, 0, 0 // SW, inv, inv, inv
|
||||
};
|
||||
float dx = cosf(degToRad(direction));
|
||||
float dy = sinf(degToRad(direction));
|
||||
|
||||
static const float DirectionVectorY[] =
|
||||
{
|
||||
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;
|
||||
*x += dx * distance;
|
||||
*x += dy * distance;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,9 +9,20 @@
|
||||
#define MATH_GAMEMATH_H_
|
||||
|
||||
#include <model/Direction.h>
|
||||
#include <model/GameObject.h>
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <cmath>
|
||||
|
||||
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>
|
||||
TVal clamp (TVal value, TMin min, TMax max)
|
||||
{
|
||||
@ -24,9 +35,12 @@ namespace farmlands {
|
||||
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);
|
||||
float distanceSq(float x0, float y0, float x1, float y1);
|
||||
|
||||
/**
|
||||
* Converts from degrees to radians
|
||||
*/
|
||||
inline float degToRad(float angle)
|
||||
{
|
||||
return angle * (float)M_PI / 360.0f;
|
||||
}
|
||||
}
|
||||
#endif /* MATH_GAMEMATH_H_ */
|
||||
|
@ -14,14 +14,10 @@ namespace model {
|
||||
enum Direction
|
||||
{
|
||||
None = 0,
|
||||
East = 1,
|
||||
North = 2,
|
||||
West = 4,
|
||||
South = 8,
|
||||
NorthEast = North | East,
|
||||
NorthWest = North | West,
|
||||
SouthWest = South | West,
|
||||
SouthEast = South | East
|
||||
East = 0,
|
||||
North = 90,
|
||||
West = 180,
|
||||
South = 270
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include <GameState.h>
|
||||
#include <model/GameObject.h>
|
||||
#include <model/Component.h>
|
||||
|
||||
#include <model/Transform.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace farmlands {
|
||||
|
@ -1,58 +1,71 @@
|
||||
/*
|
||||
* Transform.cpp
|
||||
*
|
||||
* Created on: Dec 2, 2016
|
||||
* Author: tibi
|
||||
*/
|
||||
|
||||
#include <model/GameObject.h>
|
||||
#include <model/Transform.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace farmlands {
|
||||
namespace model {
|
||||
|
||||
Transform::Transform(GameObject* obj)
|
||||
: x(0), y(0),
|
||||
w(0), h(0),
|
||||
scaleX(1), scaleY(1),
|
||||
gameObject(obj)
|
||||
{
|
||||
}
|
||||
|
||||
float Transform::globalX() const
|
||||
{
|
||||
if (gameObject->parent())
|
||||
return gameObject->parent()->transform.globalX() + x;
|
||||
|
||||
return x;
|
||||
return (gameObject->parent())
|
||||
? x + gameObject->parent()->transform.globalX()
|
||||
: x;
|
||||
}
|
||||
|
||||
float Transform::globalY() const
|
||||
{
|
||||
if (gameObject->parent())
|
||||
return gameObject->parent()->transform.globalY() + y;
|
||||
|
||||
return y;
|
||||
return (gameObject->parent())
|
||||
? y + gameObject->parent()->transform.globalY()
|
||||
: y;
|
||||
}
|
||||
|
||||
void Transform::setGlobalX(float x)
|
||||
void Transform::setGlobalX(float gx)
|
||||
{
|
||||
if (gameObject->parent())
|
||||
this->x = x - gameObject->parent()->transform.globalX();
|
||||
|
||||
this->x = x;
|
||||
x = (gameObject->parent())
|
||||
? gx - gameObject->parent()->transform.globalX()
|
||||
: gx;
|
||||
}
|
||||
|
||||
void Transform::setGlobalY(float y)
|
||||
void Transform::setGlobalY(float gy)
|
||||
{
|
||||
if (gameObject->parent())
|
||||
this->y = y - gameObject->parent()->transform.globalY();
|
||||
y = (gameObject->parent())
|
||||
? 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 */
|
||||
|
||||
|
||||
|
@ -21,15 +21,20 @@ namespace model {
|
||||
// Getters
|
||||
float globalX() const;
|
||||
float globalY() const;
|
||||
float globalScaleX() const;
|
||||
float globalScaleY() const;
|
||||
|
||||
// Setters
|
||||
void setGlobalX(float x);
|
||||
void setGlobalY(float y);
|
||||
void setGlobalX(float gx);
|
||||
void setGlobalY(float gy);
|
||||
void setGlobalScaleX(float gscaleX);
|
||||
void setGlobalScaleY(float gscaleY);
|
||||
|
||||
// Local coordinates (relative to parent)
|
||||
float x, y;
|
||||
float w, h;
|
||||
float scaleX, scaleY;
|
||||
|
||||
// Parent object
|
||||
GameObject* gameObject;
|
||||
};
|
||||
|
||||
|
@ -123,14 +123,10 @@ components::basic::Frame* parse<components::basic::Frame> (boost::property_tree:
|
||||
|
||||
components::basic::Frame* frame = new components::basic::Frame();
|
||||
|
||||
// Obtine tile set id
|
||||
// Set properties
|
||||
std::string tileSetPath = root.get<std::string>("<xmlattr>.tileSet");
|
||||
frame->tileSetId = resources::ResourceManager::instance().getId(tileSetPath);
|
||||
|
||||
// Set properties
|
||||
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");
|
||||
|
||||
return frame;
|
||||
@ -202,9 +198,11 @@ components::basic::Sprite* parse<components::basic::Sprite> (boost::property_tre
|
||||
|
||||
// Parse 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->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)
|
||||
{
|
||||
@ -451,14 +449,14 @@ model::Direction parseDirection(std::string directionStr)
|
||||
model::Direction direction = model::Direction::None;
|
||||
boost::to_lower(directionStr);
|
||||
|
||||
if (boost::contains(directionStr, "east"))
|
||||
direction = (model::Direction) (direction | model::Direction::East);
|
||||
if (boost::contains(directionStr, "north"))
|
||||
direction = (model::Direction) (direction | model::Direction::North);
|
||||
if (boost::contains(directionStr, "west"))
|
||||
direction = (model::Direction) (direction | model::Direction::West);
|
||||
if (boost::contains(directionStr, "south"))
|
||||
direction = (model::Direction) (direction | model::Direction::South);
|
||||
if (directionStr == "east")
|
||||
direction = model::Direction::East;
|
||||
if (directionStr == "north")
|
||||
direction = model::Direction::North;
|
||||
if (directionStr == "west")
|
||||
direction = model::Direction::West;
|
||||
if (directionStr == "south")
|
||||
direction = model::Direction::South;
|
||||
|
||||
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.y = root.get<float>("<xmlattr>.y", 0.0f);
|
||||
transform.w = root.get<float>("<xmlattr>.w", 1.0f);
|
||||
transform.h = root.get<float>("<xmlattr>.h", 1.0f);
|
||||
transform.scaleX = root.get<float>("<xmlattr>.scaleX", 1.0f);
|
||||
transform.scaleY = root.get<float>("<xmlattr>.scaleY", 1.0f);
|
||||
}
|
||||
|
||||
template <>
|
||||
|
Loading…
Reference in New Issue
Block a user