Compare commits

...

2 Commits

Author SHA1 Message Date
Kayne Ruse a5757748cf That didn't go as well as I'd hoped 2015-01-21 04:20:31 +11:00
Kayne Ruse f4e4728ce3 Partial solution for collision problems 2015-01-21 03:06:35 +11:00
7 changed files with 106 additions and 82 deletions
+49 -8
View File
@@ -23,13 +23,54 @@
#include <iostream> #include <iostream>
bool LocalCharacter::ProcessCollisionGrid(std::list<BoundingBox> boxList) { bool LocalCharacter::ProcessCollisionGrid(std::list<BoundingBox> boxList, Uint8* keyState) {
for(auto& box : boxList) { //skip this if there's no movement
if (box.CheckOverlap(origin + bounds)) { if (motion == 0) {
origin -= motion;
motion = {0, 0};
return true;
}
}
return false; return false;
} }
//determine the simple movement based on input
Vector2 newMotion = {0, 0};
if (keyState[SDLK_w]) {
newMotion.y -= CHARACTER_WALKING_SPEED;
}
if (keyState[SDLK_a]) {
newMotion.x -= CHARACTER_WALKING_SPEED;
}
if (keyState[SDLK_s]) {
newMotion.y += CHARACTER_WALKING_SPEED;
}
if (keyState[SDLK_d]) {
newMotion.x += CHARACTER_WALKING_SPEED;
}
bool ret = false;
for(auto& box : boxList) {
if (box.CheckCollision(origin + bounds)) {
//push the character to the closest non-contact position
Vector2 shift = box.CalcShift(origin + bounds);
origin += shift;
//set any motion in that direction to zero
if (shift.x != 0) {
newMotion.x = 0;
}
if (shift.y != 0) {
newMotion.y = 0;
}
ret = true;
}
}
//handle diagonals
if (newMotion.x != 0 && newMotion.y != 0) {
newMotion *= CHARACTER_WALKING_MOD;
}
//set the new motion
motion = newMotion;
//signal for updates
return ret;
}
+1 -1
View File
@@ -33,7 +33,7 @@ public:
LocalCharacter() = default; LocalCharacter() = default;
virtual ~LocalCharacter() = default; virtual ~LocalCharacter() = default;
bool ProcessCollisionGrid(std::list<BoundingBox>); bool ProcessCollisionGrid(std::list<BoundingBox>, Uint8* keyState);
private: private:
//NOTE: NO MEMBERS //NOTE: NO MEMBERS
+2
View File
@@ -107,6 +107,7 @@ protected:
void HandleMonsterAttack(MonsterPacket* const); void HandleMonsterAttack(MonsterPacket* const);
//player movement //player movement
void ProcessLocalCharacterMovement();
void SendLocalCharacterMovement(); void SendLocalCharacterMovement();
std::list<BoundingBox> GenerateCollisionGrid(Entity*, int tileWidth, int tileHeight); std::list<BoundingBox> GenerateCollisionGrid(Entity*, int tileWidth, int tileHeight);
@@ -150,6 +151,7 @@ protected:
//ugly references; I hate this //ugly references; I hate this
ConfigUtility& config = ConfigUtility::GetSingleton(); ConfigUtility& config = ConfigUtility::GetSingleton();
UDPNetworkUtility& network = UDPNetworkUtility::GetSingleton(); UDPNetworkUtility& network = UDPNetworkUtility::GetSingleton();
Uint8* keyState = nullptr;
}; };
#endif #endif
+33 -1
View File
@@ -175,7 +175,39 @@ void InWorld::HandleMonsterAttack(MonsterPacket* const argPacket) {
//player movement //player movement
//------------------------- //-------------------------
//TODO: add a "movement" packet type void InWorld::ProcessLocalCharacterMovement() {
//character movement
if (!localCharacter) {
return;
}
Vector2 newMotion = {0, 0};
if (keyState[SDLK_w]) {
newMotion.y -= CHARACTER_WALKING_SPEED;
}
if (keyState[SDLK_a]) {
newMotion.x -= CHARACTER_WALKING_SPEED;
}
if (keyState[SDLK_s]) {
newMotion.y += CHARACTER_WALKING_SPEED;
}
if (keyState[SDLK_d]) {
newMotion.x += CHARACTER_WALKING_SPEED;
}
//handle diagonals
if (newMotion.x != 0 && newMotion.y != 0) {
newMotion *= CHARACTER_WALKING_MOD;
}
//set the info
if (localCharacter->GetMotion() != newMotion) {
localCharacter->SetMotion(newMotion);
localCharacter->CorrectSprite();
SendLocalCharacterMovement();
}
}
void InWorld::SendLocalCharacterMovement() { void InWorld::SendLocalCharacterMovement() {
CharacterPacket newPacket; CharacterPacket newPacket;
newPacket.type = SerialPacketType::CHARACTER_MOVEMENT; newPacket.type = SerialPacketType::CHARACTER_MOVEMENT;
+6 -59
View File
@@ -36,7 +36,8 @@
InWorld::InWorld(int* const argClientIndex, int* const argAccountIndex): InWorld::InWorld(int* const argClientIndex, int* const argAccountIndex):
clientIndex(*argClientIndex), clientIndex(*argClientIndex),
accountIndex(*argAccountIndex) accountIndex(*argAccountIndex),
keyState(SDL_GetKeyState(nullptr))
{ {
//setup the utility objects //setup the utility objects
buttonImage.LoadSurface(config["dir.interface"] + "button_menu.bmp"); buttonImage.LoadSurface(config["dir.interface"] + "button_menu.bmp");
@@ -144,7 +145,7 @@ void InWorld::Update() {
std::list<BoundingBox> boxList = GenerateCollisionGrid(localCharacter, tileSheet.GetTileW(), tileSheet.GetTileH()); std::list<BoundingBox> boxList = GenerateCollisionGrid(localCharacter, tileSheet.GetTileW(), tileSheet.GetTileH());
//process the collisions //process the collisions
if (localCharacter->ProcessCollisionGrid(boxList)) { if (localCharacter->ProcessCollisionGrid(boxList, keyState)) {
localCharacter->CorrectSprite(); localCharacter->CorrectSprite();
SendLocalCharacterMovement(); SendLocalCharacterMovement();
} }
@@ -219,88 +220,34 @@ void InWorld::MouseButtonUp(SDL_MouseButtonEvent const& button) {
} }
void InWorld::KeyDown(SDL_KeyboardEvent const& key) { void InWorld::KeyDown(SDL_KeyboardEvent const& key) {
//hotkeys //hotkeys & player input
switch(key.keysym.sym) { switch(key.keysym.sym) {
case SDLK_ESCAPE: case SDLK_ESCAPE:
//TODO: the escape key should actually control menus and stuff //TODO: the escape key should actually control menus and stuff
SendLogoutRequest(); SendLogoutRequest();
return; return;
}
//character movement
if (!localCharacter) {
return;
}
Vector2 motion = localCharacter->GetMotion();
switch(key.keysym.sym) {
case SDLK_w: case SDLK_w:
motion.y -= CHARACTER_WALKING_SPEED;
break;
case SDLK_a: case SDLK_a:
motion.x -= CHARACTER_WALKING_SPEED;
break;
case SDLK_s: case SDLK_s:
motion.y += CHARACTER_WALKING_SPEED;
break;
case SDLK_d: case SDLK_d:
motion.x += CHARACTER_WALKING_SPEED; ProcessLocalCharacterMovement();
break; break;
default: default:
//DOCS: prevents wrong keys screwing with character movement //DOCS: prevents wrong keys screwing with character movement
return; return;
} }
//handle diagonals
if (motion.x != 0 && motion.y != 0) {
motion *= CHARACTER_WALKING_MOD;
}
//set the info
localCharacter->SetMotion(motion);
localCharacter->CorrectSprite();
SendLocalCharacterMovement();
} }
void InWorld::KeyUp(SDL_KeyboardEvent const& key) { void InWorld::KeyUp(SDL_KeyboardEvent const& key) {
//character movement
if (!localCharacter) {
return;
}
Vector2 motion = localCharacter->GetMotion();
switch(key.keysym.sym) { switch(key.keysym.sym) {
case SDLK_w: case SDLK_w:
motion.y = std::min(0.0, motion.y += CHARACTER_WALKING_SPEED);
break;
case SDLK_a: case SDLK_a:
motion.x = std::min(0.0, motion.x += CHARACTER_WALKING_SPEED);
break;
case SDLK_s: case SDLK_s:
motion.y = std::max(0.0, motion.y -= CHARACTER_WALKING_SPEED);
break;
case SDLK_d: case SDLK_d:
motion.x = std::max(0.0, motion.x -= CHARACTER_WALKING_SPEED); ProcessLocalCharacterMovement();
break; break;
default: default:
//DOCS: prevents wrong keys screwing with character movement //DOCS: prevents wrong keys screwing with character movement
return; return;
} }
//BUGFIX: reset cardinal direction speed on key release
if (motion.x > 0) {
motion.x = CHARACTER_WALKING_SPEED;
}
else if (motion.x < 0) {
motion.x = -CHARACTER_WALKING_SPEED;
}
if (motion.y > 0) {
motion.y = CHARACTER_WALKING_SPEED;
}
else if (motion.y < 0) {
motion.y = -CHARACTER_WALKING_SPEED;
}
//handle diagonals
if (motion.x != 0 && motion.y != 0) {
motion *= CHARACTER_WALKING_MOD;
}
//set the info
localCharacter->SetMotion(motion);
localCharacter->CorrectSprite();
SendLocalCharacterMovement();
} }
+1 -1
View File
@@ -166,7 +166,7 @@ void LobbyMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) {
//has the user selected a server on the list? //has the user selected a server on the list?
BoundingBox tmpBox = listBox; BoundingBox tmpBox = listBox;
tmpBox.h *= serverInfo.size(); tmpBox.h *= serverInfo.size();
if (tmpBox.CheckOverlap({button.x, button.y})) { if (tmpBox.CheckCollision({button.x, button.y, 0, 0})) {
selection = &serverInfo[(button.y - listBox.y)/listBox.h]; selection = &serverInfo[(button.y - listBox.y)/listBox.h];
} }
else { else {
+16 -14
View File
@@ -22,6 +22,8 @@
#ifndef BOUNDINGBOX_HPP_ #ifndef BOUNDINGBOX_HPP_
#define BOUNDINGBOX_HPP_ #define BOUNDINGBOX_HPP_
#include "vector2.hpp"
#include <type_traits> #include <type_traits>
#include <algorithm> #include <algorithm>
@@ -32,16 +34,15 @@ public:
int w, h; int w, h;
BoundingBox() = default; BoundingBox() = default;
BoundingBox(int i, int j): x(i), y(j), w(0), h(0) {};
BoundingBox(int i, int j, int k, int l): x(i), y(j), w(k), h(l) {}; BoundingBox(int i, int j, int k, int l): x(i), y(j), w(k), h(l) {};
~BoundingBox() = default; ~BoundingBox() = default;
BoundingBox& operator=(BoundingBox const&) = default; BoundingBox& operator=(BoundingBox const&) = default;
int Size() { int Size() {
return std::max(w*h,0); return (w-x) * (h-y);
} }
bool CheckOverlap(BoundingBox rhs) { bool CheckCollision(BoundingBox rhs) {
return !( return !(
x >= rhs.x + rhs.w || x >= rhs.x + rhs.w ||
y >= rhs.y + rhs.h || y >= rhs.y + rhs.h ||
@@ -49,24 +50,25 @@ public:
rhs.y >= y + h); rhs.y >= y + h);
} }
BoundingBox CalcOverlap(BoundingBox rhs) { Vector2 CalcShift(BoundingBox rhs) {
if (!CheckOverlap(rhs)) { if (!CheckCollision(rhs)) {
return {0, 0, 0, 0}; return {0, 0};
} }
BoundingBox ret;
ret.x = std::max(x, rhs.x); //DOCS: Given two BoundingBox objects, how does the other have to move so that they are no longer colliding?
ret.y = std::max(y, rhs.y); Vector2 horizontal = {0, 0};
ret.w = std::min(x+w, rhs.x+rhs.w) - ret.x; Vector2 vertical = {0, 0};
ret.h = std::min(y+h, rhs.y+rhs.h) - ret.y;
return ret; horizontal.x = std::abs(x + w - rhs.x) < std::abs(rhs.x + rhs.w - x) ? x + w - rhs.x -1 : -(rhs.x + rhs.w - x -1);
vertical.y = std::abs(y + h - rhs.x) < std::abs(rhs.y + rhs.h - y) ? y + h - rhs.y -1 : -(rhs.y + rhs.h - y -1);
return std::abs(vertical.y) < std::abs(horizontal.x) ? vertical : horizontal;
} }
}; };
//This is explicitly a POD //This is explicitly a POD
static_assert(std::is_pod<BoundingBox>::value, "BoundingBox is not a POD"); static_assert(std::is_pod<BoundingBox>::value, "BoundingBox is not a POD");
#include "vector2.hpp"
//operators //operators
inline BoundingBox operator+(BoundingBox b, Vector2 v) { inline BoundingBox operator+(BoundingBox b, Vector2 v) {
return {b.x + (int)v.x, b.y + (int)v.y, b.w, b.h}; return {b.x + (int)v.x, b.y + (int)v.y, b.w, b.h};