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 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/import/include}&quot;"/>
</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="&quot;${workspace_loc:/Farmlands/src}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/Farmlands/import/include}&quot;"/>
</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="&quot;${workspace_loc:/Farmlands/src}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/Farmlands/import/include}&quot;"/>
</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="&quot;${workspace_loc:/Farmlands/src}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/Farmlands/import/include}&quot;"/>
</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"/>

View File

@ -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 />

View File

@ -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 />

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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);
}
}

View File

@ -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;
m_currentState = stateId;
m_currentFrame = 0;
m_currentFrameTimeLeft = currentFrame().duration;
// 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)
{

View File

@ -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);

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 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);
}
}

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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_ */

View File

@ -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
};
}

View File

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

View File

@ -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 */

View File

@ -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;
};

View File

@ -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 <>