Skip to content

added arrow to target cave #189

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions src/caveexpress/client/CaveExpressClientMap.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#include "caveexpress/client/CaveExpressClientMap.h"
#include "caveexpress/server/entities/Player.h"
#include "caveexpress/shared/CaveExpressEntityType.h"
#include "caveexpress/shared/CaveExpressCooldown.h"
#include "caveexpress/client/entities/ClientWindowTile.h"
#include "caveexpress/client/entities/ClientCaveTile.h"
#include "caveexpress/shared/network/messages/ProtocolMessages.h"
#include "common/Math.h"
#include "common/ThemeType.h"
#include "common/vec2.h"
#include "particles/Bubble.h"
Expand All @@ -20,6 +22,8 @@
#include "common/Log.h"
#include "service/ServiceProvider.h"
#include "common/DateUtil.h"
#include "ui/nodes/UINodeSprite.h"
#include "ui/windows/IUIMapWindow.h"
#include <SDL.h>
#include <SDL_image.h>

Expand Down Expand Up @@ -63,6 +67,42 @@ void CaveExpressClientMap::renderWater (int x, int y) const
}
}

// _player arrow to cave
void CaveExpressClientMap::renderArrow () const
{
ClientPlayer *player = getPlayer();
if (!player)
return;
UINodeSpriteRot* arrow = UI::get().getNode<UINodeSpriteRot>(UI_WINDOW_MAP, UINODE_TARGET_ARROW);
float ang = arrow->_angle;
if (ang < 0.f)
return;

float xdir = cosf(ang), ydir = -sinf(ang);

int x1, y1;
player->getScreenPos(x1,y1);
const vec2& s = player->getSize();
y1 -= s.y / 2;
const float d1 = 40.f, d2 = 90.f;
int x2 = x1 + xdir * d2;
int y2 = y1 + ydir * d2;
x1 += xdir * d1;
y1 += ydir * d1;
_frontend->renderLine(x1, y1, x2, y2, colorGreen);

const float a = M_PI + M_PI / 6.f, d3 = 15.f;
float xa = cosf(ang + a), ya = -sinf(ang + a);
int x3 = x2 + xa * d3;
int y3 = y2 + ya * d3;
const float b = M_PI - M_PI / 6.f;
_frontend->renderLine(x2, y2, x3, y3, colorGreen);
float xb = cosf(ang + b), yb = -sinf(ang + b);
int x4 = x2 + xb * d3;
int y4 = y2 + yb * d3;
_frontend->renderLine(x2, y2, x4, y4, colorGreen);
}

bool CaveExpressClientMap::drop ()
{
if (isPause() || !isActive())
Expand Down Expand Up @@ -267,6 +307,7 @@ void CaveExpressClientMap::renderEnd (int x, int y) const
if (_target)
_frontend->renderTarget(_target);
renderWater(x, y);
renderArrow();
}

int CaveExpressClientMap::renderCooldownDescription (uint32_t cooldownIndex, int x, int y, int w, int h) const
Expand Down
1 change: 1 addition & 0 deletions src/caveexpress/client/CaveExpressClientMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class CaveExpressClientMap: public ClientMap {
float _wind = 0.0f;
mutable RenderTarget* _target = nullptr;

void renderArrow () const;
void renderWater (int x, int y) const;
SDL_Rect getWaterRect(int x, int y) const;
void couldNotFindEntity (const std::string& prefix, uint16_t id) const override;
Expand Down
7 changes: 7 additions & 0 deletions src/caveexpress/client/network/TargetCaveHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,14 @@ class TargetCaveHandler: public ClientProtocolHandler<TargetCaveMessage> {

void execute(const TargetCaveMessage* msg) override
{
const float ang = msg->getAngle();
UINodeSpriteRot* arrow = UI::get().getNode<UINodeSpriteRot>(UI_WINDOW_MAP, UINODE_TARGET_ARROW);
arrow->_angle = ang;

const uint8_t caveNumber = msg->getCaveNumber();
if (caveNumber >= 200) // from update
return;

UINodeSprite* node = UI::get().getNode<UINodeSprite>(UI_WINDOW_MAP, UINODE_TARGETCAVEID);
if (caveNumber == 0) {
node->clearSprites();
Expand Down
4 changes: 4 additions & 0 deletions src/caveexpress/client/ui/windows/UIMapWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ void UIMapWindow::initHudNodes()
_panel->add(pkgLeft);

add(_panel);

UINodeSpriteRot *arrow = new UINodeSpriteRot(_frontend, spriteHeight, spriteHeight);
arrow->setId(UINODE_TARGET_ARROW);
add(arrow);
}

}
44 changes: 38 additions & 6 deletions src/caveexpress/server/entities/Player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "caveexpress/shared/CaveExpressCooldown.h"
#include "caveexpress/shared/CaveExpressSoundType.h"
#include "caveexpress/shared/constants/ConfigVars.h"
#include <cmath>

namespace caveexpress {

Expand All @@ -28,7 +29,8 @@ const float gravityScale = 0.3f;
Player::Player (Map& map, ClientId clientId) :
IEntity(EntityTypes::PLAYER, map), _touching(nullptr), _invulnerableTime(0u), _powerUpTime(0u), _collectedNPC(nullptr), _acceleration(b2Vec2_zero), _fingerAcceleration(
false), _accelerateX(0), _accelerateY(0), _clientId(clientId), _lastAccelerate(0), _name(""), _lastFruitCollected(0), _hitpoints(
0), _lives(0), _fruitsCollectedInARow(0), _revoluteJoint(nullptr), _crashReason(CRASH_NONE) {
0), _lives(0), _fruitsCollectedInARow(0), _revoluteJoint(nullptr), _crashReason(CRASH_NONE)
{
_godMode = Config.getConfigVar(GOD_MODE);
_maxHitPoints = Config.getConfigVar(MAX_HITPOINTS);
_hitpoints = _maxHitPoints->getIntValue();
Expand All @@ -39,6 +41,8 @@ Player::Player (Map& map, ClientId clientId) :
setAnimationType(Animations::ANIMATION_IDLE);
setState(PlayerState::PLAYER_IDLE);
memset(_collectedEntities, 0, sizeof(_collectedEntities));
_targetCavePos.x = -1.f;
_targetCavePos.y = -1.f;
}

Player::~Player ()
Expand Down Expand Up @@ -154,6 +158,8 @@ void Player::update (uint32_t deltaTime)
{
IEntity::update(deltaTime);

sendTargetCaveAngle();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doing this every frame is a waste of traffic. it would be better to send the position once the target cave is selected and do the whole arrow thing client side.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I don't know yet how to do it on client side, which files/classes would I need to edit?


if (isCrashed()) {
// before we crash, we should drop the stuff we are carrying
drop();
Expand Down Expand Up @@ -462,7 +468,7 @@ bool Player::collect (CollectableEntity* entity)
break;
}
if (EntityTypes::isStone(entityType)) {
GameEvent.sendTargetCave(ClientIdToClientMask(_clientId), 100);
GameEvent.sendTargetCave(ClientIdToClientMask(_clientId), 100, -1.f);
Achievements::COLLECT_10_STONES.unlock();
Achievements::COLLECT_100_STONES.unlock();
}
Expand All @@ -481,7 +487,7 @@ void Player::drop ()
if (EntityTypes::isStone(*entityType)) {
Stone *entity = new Stone(_map, getPos().x, getPos().y, this);
entity->createBody();
GameEvent.sendTargetCave(ClientIdToClientMask(_clientId), 0);
GameEvent.sendTargetCave(ClientIdToClientMask(_clientId), 0, -1.f);
} else if (EntityTypes::isBomb(*entityType)) {
Bomb *entity = new Bomb(_map, getPos().x, getPos().y, this);
entity->createBody();
Expand Down Expand Up @@ -629,17 +635,43 @@ void Player::setPlatform (Platform* entity)
npc->resetTriggerMovement();
}

void Player::setCollectedNPC(NPCFriendly *npc) {
static float GetAngle(float x, float y)
{
if (x == 0.f && y == 0.f)
return 0.f;

if (y == 0.f)
return (x < 0.f) ? M_PI : 0.f;
else
return (y < 0.f) ? atan2f(-y, x) : (2.f * M_PI - atan2f(y, x));
}

void Player::sendTargetCaveAngle()
{
if (_collectedNPC == nullptr)
return;
if (_collectedNPC->getTargetCave() == nullptr)
return;

_targetCavePos = _collectedNPC->getTargetCave()->getPos();
const b2Vec2 dir = _targetCavePos - getPos();
const float angle = GetAngle(dir.x, dir.y);

GameEvent.sendTargetCave(ClientIdToClientMask(_clientId), 200, angle);
}

void Player::setCollectedNPC(NPCFriendly *npc)
{
// we can't collect a npc if we have collected something else
if (npc && !isFree())
return;

_collectedNPC = npc;
if (npc != nullptr) {
npc->setCollected();
GameEvent.sendTargetCave(ClientIdToClientMask(_clientId), npc->getTargetCaveNumber());
GameEvent.sendTargetCave(ClientIdToClientMask(_clientId), npc->getTargetCaveNumber(), -1.f);
} else {
GameEvent.sendTargetCave(ClientIdToClientMask(_clientId), 0);
GameEvent.sendTargetCave(ClientIdToClientMask(_clientId), 0, -1.f);
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/caveexpress/server/entities/Player.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class Player: public IEntity {
uint32_t _powerUpTime;

NPCFriendly* _collectedNPC;
b2Vec2 _targetCavePos;

b2Vec2 _acceleration;

Expand Down Expand Up @@ -127,6 +128,7 @@ class Player: public IEntity {
void createBody (const b2Vec2 &pos);

void setCollectedNPC(NPCFriendly *npc);
void sendTargetCaveAngle();
void reset ();

ClientId getClientId () const;
Expand Down
4 changes: 2 additions & 2 deletions src/caveexpress/server/events/GameEventHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ void GameEventHandler::announceTargetCave(int clientMask, const NPCFriendly& npc
_serviceProvider->getNetwork().sendToClients(clientMask, msg);
}

void GameEventHandler::sendTargetCave(int clientMask, uint8_t number) const {
const TargetCaveMessage msg(number);
void GameEventHandler::sendTargetCave(int clientMask, uint8_t number, float angle) const {
const TargetCaveMessage msg(number, angle);
_serviceProvider->getNetwork().sendToClients(clientMask, msg);
}

Expand Down
2 changes: 1 addition & 1 deletion src/caveexpress/server/events/GameEventHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class GameEventHandler: public NonCopyable {
void announceTargetCave (int clientMask, const NPCFriendly& npc, int16_t delayMillis) const;

// inform the client about the target cave number the npc wants to get carried to
void sendTargetCave (int clientMask, uint8_t number) const;
void sendTargetCave (int clientMask, uint8_t number, float angle) const;

// inform the clients that the given entity changed its animation
// used to e.g. change a npc animation to walking
Expand Down
14 changes: 11 additions & 3 deletions src/caveexpress/shared/network/messages/TargetCaveMessage.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,35 @@ namespace caveexpress {
class TargetCaveMessage: public IProtocolMessage {
private:
uint8_t _targetCave; // 0 none, 100 stone
float _angle; // arrow angle to target cave -1 if none
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is no need to send this as a 4 byte float value - uint16_t would be enough here.


public:
TargetCaveMessage(uint8_t targetCave) :
IProtocolMessage(protocol::PROTO_TARGETCAVE), _targetCave(targetCave) {
TargetCaveMessage(uint8_t targetCave, float angle) :
IProtocolMessage(protocol::PROTO_TARGETCAVE), _targetCave(targetCave), _angle(angle) {
}

PROTOCOL_CLASS_FACTORY(TargetCaveMessage);
explicit TargetCaveMessage(ByteStream& input) :
IProtocolMessage(protocol::PROTO_TARGETCAVE) {
IProtocolMessage(protocol::PROTO_TARGETCAVE)
{
_targetCave = input.readByte();
_angle = input.readFloat();
}

void serialize(ByteStream& out) const override
{
out.addByte(_id);
out.addByte(_targetCave);
out.addFloat(_angle);
}

inline uint8_t getCaveNumber() const {
return _targetCave;
}

inline float getAngle() const {
return _angle;
}
};

}
4 changes: 4 additions & 0 deletions src/modules/ui/nodes/UINodeSprite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ UINodeSprite::UINodeSprite (IFrontend *frontend, int spriteWidth, int spriteHeig
0.0f), _movementSpeed(0.0f), _movementActive(false) {
}

UINodeSpriteRot::UINodeSpriteRot (IFrontend *frontend, int spriteWidth, int spriteHeight)
: UINodeSprite(frontend, spriteWidth, spriteHeight)
{
}

UINodeSprite::UINodeSprite (IFrontend *frontend, const EntityType& type, const Animation& animation, int spriteWidth, int spriteHeight) :
UINode(frontend), _offset(0), _borderWidth(-1.0f), _borderHeight(-1.0f), _spriteWidth(
Expand Down
8 changes: 8 additions & 0 deletions src/modules/ui/nodes/UINodeSprite.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ class UINodeSprite: public UINode {
void update (uint32_t deltaTime) override;
};

class UINodeSpriteRot: public UINodeSprite {
public:
float _angle = -1.f;

UINodeSpriteRot (IFrontend *frontend, int spriteWidth = -1, int spriteHeight = -1);
};


inline void UINodeSprite::addSprite (const SpritePtr& sprite)
{
_sprites.push_back(sprite);
Expand Down
1 change: 1 addition & 0 deletions src/modules/ui/windows/IUIMapWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#define UINODE_SECONDS_REMAINING "seconds"
#define UINODE_MAP "map"
#define UINODE_TARGETCAVEID "targetcave"
#define UINODE_TARGET_ARROW "target_arrow"
#define UINODE_COLLECTED "collected"
#define UINODE_TRANSFERS "transfers"
#define UINODE_TRANSFERS_LEFT "transfers_left"
Expand Down
Loading