I am trying to replicate the effect from this link Side way car movement I am using levelHelper to design the car. but unable to replicate the effect. I Think i am doing mistake in revolute joint. Here is the code i am trying.
#include "GamePlayScene.h"
#include "LevelManager.h"
#include "Constants.h"
#include "iostream"
void GamePlayScene::InitPhysics()
{
b2Vec2 gravity;
gravity.Set(0.0f, -10.0f);
m_pB2World = new b2World(gravity);
m_pB2World->SetAllowSleeping(true);
m_pB2World->SetContinuousPhysics(true);
m_pDebugDraw = new GLESDebugDraw( LevelHelperLoader::pixelsToMeterRatio() );
PTM_RATIO = LevelHelperLoader::pixelsToMeterRatio();
m_pB2World->SetDebugDraw(m_pDebugDraw);
m_pLoader= new LevelHelperLoader("track7.plhs");
m_pLoader->addObjectsToWorld(m_pB2World,this);
m_pB2World->ClearForces();
//m_pB2World->DestroyJoint()
LHSprite * carBody = m_pLoader->spriteWithUniqueName("CarBody");
m_pCarBody = carBody->getBody();
m_pCarBody->GetFixtureList()->SetDensity(CAR_BODY_DENSITY);
m_pCarBody->ResetMassData();
m_pCarBody->GetFixtureList()->SetFriction(CAR_BODY_FRICTION);
m_pCarBody->GetFixtureList()->SetRestitution(CAR_BODY_RESTITUTION);
LHSprite * chasis = m_pLoader->spriteWithUniqueName("Chasis");
m_pChasis = chasis->getBody();
m_pChasis->GetFixtureList()->SetDensity(CHASIS_DENSITY);
m_pChasis->ResetMassData();
m_pChasis->GetFixtureList()->SetFriction(CHASIS_FRICTION);
m_pChasis->GetFixtureList()->SetRestitution(CHASIS_RESTITUTION);
//m_pChasis->remove
LHSprite * frontWheel = m_pLoader->spriteWithUniqueName("FrontWheel");
m_pFrontWheel = frontWheel->getBody();
m_pFrontWheel->GetFixtureList()->SetDensity(FRONT_WHEEL_DENSITY);
m_pFrontWheel->ResetMassData();
m_pFrontWheel->GetFixtureList()->SetFriction(FRONT_WHEEL_FRICTION);
m_pFrontWheel->GetFixtureList()->SetRestitution(FRONT_WHEEL_RESTITUTION);
LHSprite * rearWheel = m_pLoader->spriteWithUniqueName("RearWheel");
m_pRearWheel = rearWheel->getBody();
m_pRearWheel->GetFixtureList()->SetDensity(REAR_WHEEL_DENSITY);
m_pRearWheel->ResetMassData();
m_pRearWheel->GetFixtureList()->SetFriction(REAR_WHEEL_FRICTION);
m_pRearWheel->GetFixtureList()->SetRestitution(REAR_WHEEL_RESTITUTION);
LHSprite * frontDamper = m_pLoader->spriteWithUniqueName("FrontDamper");
m_pFrontDamper = frontDamper->getBody();
m_pFrontDamper->GetFixtureList()->SetDensity(FRONT_DAMPER_DENSITY);
m_pFrontDamper->ResetMassData();
m_pFrontDamper->GetFixtureList()->SetFriction(FRONT_DAMPER_FRICTION);
m_pFrontDamper->GetFixtureList()->SetRestitution(FRONT_DAMPER_RESTITUTION);
LHSprite * rearDamper = m_pLoader->spriteWithUniqueName("RearDamper");
m_pRearDamper = rearDamper->getBody();
m_pRearDamper->GetFixtureList()->SetDensity(REAR_DAMPER_DENSITY);
m_pRearDamper->ResetMassData();
m_pRearDamper->GetFixtureList()->SetFriction(REAR_DAMPER_FRICTION);
m_pRearDamper->GetFixtureList()->SetRestitution(REAR_DAMPER_RESTITUTION);
b2PolygonShape * shape = (b2PolygonShape *)m_pChasis->GetFixtureList()->GetShape();
//shape->SetAsBox(
LHJoint * frontPrismJoint = frontDamper->jointWithUniqueName("FrontDamperChasis");
LH_JOINT_TYPE type2 = frontPrismJoint->getType();
if(type2 == LH_PRISMATIC_JOINT)
{
//m_pFrontPrismJoint = (b2PrismaticJoint *)frontPrismJoint;
//b2PrismaticJointDef prismJointDef;
frontPrismJointDef = new b2PrismaticJointDef();
//b2Vec2 anchor = m_pFrontDamper->GetWorldCenter() - m_pChasis->GetWorldCenter();
frontPrismJointDef->Initialize(m_pChasis,m_pFrontDamper, m_pFrontDamper->GetWorldCenter(), b2Vec2(0, 1));
frontPrismJointDef->enableLimit = FRONT_PRISM_JOINT_ENABLE_LIMIT;
frontPrismJointDef->enableMotor = FRONT_PRISM_JOINT_ENABLE_MOTOR;
frontPrismJointDef->lowerTranslation = FRONT_PRISM_JOINT_LOWERTRANSLATION;
frontPrismJointDef->upperTranslation = FRONT_PRISM_JOINT_UPPERTRANSLATION;
frontPrismJointDef->maxMotorForce = FRONT_PRISM_JOINT_MAXMOTORFORCE;
//b2Joint * joint = (b2Joint *)frontPrismJoint;
//frontPrismJointDef->
m_pFrontSpring = (b2PrismaticJoint *)m_pB2World->CreateJoint(frontPrismJointDef);
//m_pB2World->DestroyJoint(joint);
}
LHJoint * rearPrismJoint = rearDamper->jointWithUniqueName("RearDamperChasis");
type2 = rearPrismJoint->getType();
if(type2 == LH_PRISMATIC_JOINT)
{
//m_pRearPrismJoint = (b2PrismaticJoint *)rearPrismJoint;
rearPrismJointDef = new b2PrismaticJointDef();
rearPrismJointDef->Initialize(m_pChasis, m_pRearDamper, m_pRearDamper->GetWorldCenter(), b2Vec2(0, 1));
rearPrismJointDef->enableLimit = REAR_PRISM_JOINT_ENABLE_LIMIT;
rearPrismJointDef->enableMotor = REAR_PRISM_JOINT_ENABLE_MOTOR;
rearPrismJointDef->lowerTranslation = REAR_PRISM_JOINT_LOWERTRANSLATION;
rearPrismJointDef->upperTranslation = REAR_PRISM_JOINT_UPPERTRANSLATION;
rearPrismJointDef->maxMotorForce = REAR_PRISM_JOINT_MAXMOTORFORCE;
m_pRearSpring = (b2PrismaticJoint *)m_pB2World->CreateJoint(rearPrismJointDef);
}
LHJoint * frontRevoluteJoint = frontWheel->jointWithUniqueName("FrontDamperWheel");
//frontWheel->jo
LH_JOINT_TYPE type = frontRevoluteJoint->getType();
if(type == LH_REVOLUTE_JOINT)
{
m_pFrontMotor = (b2RevoluteJoint *)frontRevoluteJoint;
frontRevoluteJointDef = new b2RevoluteJointDef();
frontRevoluteJointDef->Initialize(m_pFrontDamper, m_pFrontWheel, m_pFrontWheel->GetWorldCenter());
frontRevoluteJointDef->motorSpeed = FRONT_REVOLUTE_JOINT_MOTORSPEED;
frontRevoluteJointDef->maxMotorTorque = FRONT_REVOLUTE_JOINT_MAXMOTORTORQUE;
frontRevoluteJointDef->enableMotor = FRONT_REVOLUTE_JOINT_ENABLE_MOTOR;
m_fFrontMotorSpeed = FRONT_REVOLUTE_JOINT_MOTORSPEED;
m_fFrontMaxMotorTorque = FRONT_REVOLUTE_JOINT_MAXMOTORTORQUE;
m_pFrontMotor = (b2RevoluteJoint *)m_pB2World->CreateJoint(frontRevoluteJointDef);
}
LHJoint * rearRevoluteJoint = rearWheel->jointWithUniqueName("RearDamperWheel");
type = rearRevoluteJoint->getType();
if(type == LH_REVOLUTE_JOINT)
{
//m_pRearRevoluteJoint = (b2RevoluteJoint *)rearRevoluteJoint;
rearRevoluteJointDef = new b2RevoluteJointDef();
rearRevoluteJointDef->Initialize(m_pRearDamper, m_pRearWheel, m_pRearWheel->GetWorldCenter());// - b2Vec2(0.1f,0.0f));
rearRevoluteJointDef->motorSpeed = REAR_REVOLUTE_JOINT_MOTORSPEED;
rearRevoluteJointDef->maxMotorTorque = REAR_REVOLUTE_JOINT_MAXMOTORTORQUE;
rearRevoluteJointDef->enableMotor = REAR_REVOLUTE_JOINT_ENABLE_MOTOR;
m_fRearMotorSpeed = REAR_REVOLUTE_JOINT_MOTORSPEED;
m_fRearMaxMotorTorque = REAR_REVOLUTE_JOINT_MAXMOTORTORQUE;
//revoluteJointDef.
m_pRearMotor = (b2RevoluteJoint *)m_pB2World->CreateJoint(rearRevoluteJointDef);
//m_fMotorSpeed = m_pRearMotor->GetMotorSpeed();
}
}
void GamePlayScene::ccTouchesBegan(cocos2d::CCSet *pTouches, CCEvent *pEvent)
{
CCTouch * touch = (CCTouch *)(pTouches->anyObject());
CCPoint location = touch->getLocationInView();
location = CCDirector::sharedDirector()->convertToGL(location);
if(location.x > mSize.width/2)
{
bIsAcceleration = true;
bIsBrake = false;
m_pFrontMotor->EnableMotor(true);
m_pRearMotor->EnableMotor(true);
//m_pFrontWheel->SetLinearVelocity(b2Vec2(-20.0f, 0.0f));
direction = 1;
oppositeDirection = -1;
}
else
{
m_pFrontMotor->EnableMotor(true);
m_pRearMotor->EnableMotor(true);
bIsAcceleration = false;
bIsBrake = true;
direction = -1;
oppositeDirection = 1;
//m_pRearWheel->SetLinearVelocity(b2Vec2(25.0f, 0.0f));
}
}
void GamePlayScene::ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent)
{
//bIsAcceleration=true;
}
void GamePlayScene::ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent)
{
bIsAcceleration=false;
bIsBrake = false;
//direction *= -1;
//m_pFrontMotor->EnableMotor(false);
}
void GamePlayScene::clickOnBackwardButn(CCObject * pSender)
{
bIsAcceleration = false;
m_pFrontMotor->EnableMotor(false);
m_pRearMotor->EnableMotor(false);
//m_fMotorSpeed = 0.0;
m_pRearMotor->SetMotorSpeed(-50.0f);
m_pFrontMotor->SetMotorSpeed(-50.0f);
m_pRearMotor->SetMaxMotorTorque(50.0f);
m_pFrontMotor->SetMaxMotorTorque(50.0f);
//m_pRearWheel->SetLinearVelocity(b2Vec2(-(10.0f),0.0f));
}
void GamePlayScene::clickOnForwardButn(CCObject * pSender)
{
m_pFrontMotor->EnableMotor(true);
m_pRearMotor->EnableMotor(true);
bIsAcceleration = true;
//m_pFrontWheel->SetLinearVelocity(b2Vec2(15.0f + m_fVelocityAcceleration,0.0f));
}
void GamePlayScene::draw()
{
CCLayer::draw();
ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position );
kmGLPushMatrix();
m_pB2World->DrawDebugData();
kmGLPopMatrix();
}
void GamePlayScene::update(float dt)
{
b2Vec2 position=m_pFrontWheel->GetPosition();
int x=position.x*32.0f;
int y=position.y*32.0f;
this->setPositionX(480.0f*90/100 + -x);
if(bIsAcceleration)
{
m_pFrontMotor->SetMotorSpeed(30 * M_PI * direction);
m_pFrontMotor->SetMaxMotorTorque(34);
m_pRearMotor->SetMotorSpeed(30 * M_PI * direction);
m_pRearMotor->SetMaxMotorTorque(24);
//m_pChasis->ApplyTorque(20 * direction);
}
else if(bIsBrake)
{
m_pFrontMotor->SetMotorSpeed(30 * M_PI * direction);
m_pFrontMotor->SetMaxMotorTorque(24);
m_pRearMotor->SetMotorSpeed(30 * M_PI * direction);
m_pRearMotor->SetMaxMotorTorque(34);
//m_pCarBody->ApplyTorque(30 * direction);
}
else
{
m_pFrontMotor->SetMotorSpeed(0.0f);
m_pFrontMotor->SetMaxMotorTorque(0.5f);
m_pRearMotor->SetMotorSpeed(0.0f);
m_pRearMotor->SetMaxMotorTorque(0.5f);
}
/*if(m_fMotorSpeed >= 50.0f)
{
m_fMotorSpeed = 50.0f;
}*/
m_pFrontSpring->SetMaxMotorForce(10 + abs(100 * pow(m_pFrontSpring->GetJointTranslation(), 2)));
m_pFrontSpring->SetMotorSpeed(-4*pow(m_pFrontSpring->GetJointTranslation(), 1));
m_pRearSpring->SetMaxMotorForce(30 + abs(100 * pow(m_pRearSpring->GetJointTranslation(), 2)));
m_pRearSpring->SetMotorSpeed((m_pRearSpring->GetMotorSpeed() - 10*m_pRearSpring->GetJointTranslation())*0.4);
int32 velocityIterations = 8;
int32 positionIterations = 6;
m_pB2World->Step(dt, velocityIterations, positionIterations);
}
void GamePlayScene::menuCloseCallback(CCObject* pSender)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
CCMessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
#else
CCDirector::sharedDirector()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
#endif
}
Related
I've been trying to create a dynamic light effect with cocos2d-x, but I cannot find a good tutorial for the 4.0 version.
For the context, I'm developping a top-down game for as a personnal project. The light would spread directly in front of the player like a flash-light, lighting every object in front of him and "colliding" with the walls and entities
The Shader hint
I've found multiple repos creating a custom light effect with cocos2d-x, but they all use the 3.0 version. The 4.0 version changed how the OpenGL code is managed in the Cocos backend.
Here's the repos I've found :
https://github.com/CodeAndWeb/cocos2d-x-dynamic-lighting
https://github.com/zerodarkzone/Cocos2d-x-lights
https://github.com/wantnon2/EffectNodes-for-cocos2dx
I've also read the Cocos2d-x Gitbook which explains what exactly changed in the CCSprite file.
Since I'm a beginner to Cocos2d-x and shader rendering, I did not understand what I had to change to make the old repos work ..
The polygon hint
I tried to create a VisionZone that would be a Cocos2d-x Node. The node would have a physic body colliding with the walls. On collision, the shape would update and adapt its shape.
Here's what the code would look like :
VisionZone.h
class VisionZone : public Node {
public:
static std::vector<Vec2> sm_shapeCollisionPoints;
static VisionZone *create(Vec2 origin, int visionDetail);
bool init() override;
void update(float delta) override;
void UpdateWithPlayer(Vec2 playerPos);
private:
void CreateNewPhysicBody(std::vector<Vec2> &points);
void UpdateShapeAndRedraw();
static bool IsInLine(Vec2 segmentStart, Vec2 segmentEnd, Vec2 point);
void CompareWithContactPoints();
void Rotate();
std::vector<Vec2> m_nonCollidedSegmentsEnds;
std::vector<Vec2> m_collidedSegmentsEnds;
Vec2 m_origin;
DrawNode *m_pVisionZoneDrawer;
int m_visionDetail;
VisionZone.cpp
std::vector<Vec2> VisionZone::sm_shapeCollisionPoints = {};
VisionZone *VisionZone::create(Vec2 origin, int visionDetail) {
auto *_obj = new(std::nothrow) VisionZone();
if (_obj && _obj->init()) {
_obj->m_origin = origin;
_obj->m_visionDetail = visionDetail;
int mid = std::floor(_obj->m_visionDetail * 0.5);
for (int i = -(mid); i <= mid; i++) {
_obj->m_nonCollidedSegmentsEnds.emplace_back(
static_cast<float>(_obj->m_origin.x + float(i) * 1.3f), _obj->m_origin.y + 300
);
}
_obj->m_collidedSegmentsEnds = _obj->m_nonCollidedSegmentsEnds;
std::vector<Vec2> _points = _obj->m_nonCollidedSegmentsEnds;
_points.emplace_back(_obj->m_origin);
_obj->CreateNewPhysicBody(_points);
} else
CC_SAFE_DELETE(_obj);
return _obj;
}
bool VisionZone::init() {
if (!Node::init()) return false;
m_pVisionZoneDrawer = DrawNode::create();
m_pVisionZoneDrawer->setPosition(m_origin);
assert(m_pVisionZoneDrawer);
addChild(m_pVisionZoneDrawer);
return true;
}
void VisionZone::update(float delta) {
Node::update(delta);
CompareWithContactPoints();
Rotate();
UpdateShapeAndRedraw();
}
void VisionZone::UpdateWithPlayer(Vec2 playerPos) {
m_origin = playerPos;
setPosition(m_origin);
}
void VisionZone::CreateNewPhysicBody(std::vector<Vec2> &points) {
points.push_back(m_origin);
PhysicsBody *_body = PhysicsBody::createEdgePolygon(
&points.front(),
int(points.size()),
PHYSICSBODY_MATERIAL_DEFAULT,
1
);
_body->setCategoryBitmask(vision_zone_collision_bitmask);
_body->setCollisionBitmask(map_collision_bitmask);
_body->setContactTestBitmask(true);
_body->setDynamic(false);
setPhysicsBody(_body);
}
bool VisionZone::IsInLine(Vec2 segmentStart, Vec2 segmentEnd, Vec2 point) {
float _startToPoint = sqrt(pow((segmentStart.x - point.x), 2) + pow((segmentStart.y - point.y), 2));
float _pointToEnd = sqrt(pow((point.x - segmentEnd.x), 2) + pow((point.y - segmentEnd.y), 2));
float _startToEnd = sqrt(pow((segmentStart.x - segmentEnd.x), 2) + pow((segmentStart.y - segmentEnd.y), 2));
return (_startToPoint + _pointToEnd == _startToEnd);
}
void VisionZone::CompareWithContactPoints() {
if (sm_shapeCollisionPoints.empty()) {
m_collidedSegmentsEnds = {m_origin, m_nonCollidedSegmentsEnds.front(), m_nonCollidedSegmentsEnds.back()};
return;
}
for (Vec2 &_nonCollidedEnd: m_nonCollidedSegmentsEnds) {
for (Vec2 &_contactPoint: sm_shapeCollisionPoints) {
if (IsInLine(m_origin, _nonCollidedEnd, _contactPoint)) {
Vec2 _midPoint = (m_nonCollidedSegmentsEnds.front() + m_nonCollidedSegmentsEnds.back()) / 2;
if (IsInLine(m_nonCollidedSegmentsEnds.front(), _midPoint, _contactPoint)) {
m_collidedSegmentsEnds = {
m_origin, sm_shapeCollisionPoints.front(), sm_shapeCollisionPoints.back(),
m_nonCollidedSegmentsEnds.back()
};
} else if (IsInLine(_midPoint, m_nonCollidedSegmentsEnds.back(), _contactPoint)) {
m_collidedSegmentsEnds = {
m_origin, m_nonCollidedSegmentsEnds.front(), sm_shapeCollisionPoints.front(),
sm_shapeCollisionPoints.back()
};
}
}
}
}
}
void VisionZone::Rotate() {
float _distanceX = InputManager::GetCursorPosX() - getPositionX();
float _distanceY = InputManager::GetCursorPosY() - getPositionY();
float _angle = atan2(_distanceY, _distanceX) * 180.f / static_cast<float>(M_PI);
setRotation(_angle);
}
void VisionZone::UpdateShapeAndRedraw() {
PhysicsShape *_newShape = getPhysicsBody()->addShape(PhysicsShapePolygon::create(
m_collidedSegmentsEnds.data(), int(m_collidedSegmentsEnds.size()))
);
assert(_newShape);
m_pVisionZoneDrawer->clear();
m_pVisionZoneDrawer->drawSolidPoly(
&m_collidedSegmentsEnds.front(),
m_collidedSegmentsEnds.size(),
Color4F(1.f, 0.94, 0.7, 1)
);
}
CollisionManager.cpp
#include "CollisionManager.h"
#include "Utility/Bitmasks.h"
USING_NS_CC;
EventListenerPhysicsContact *CollisionManager::m_contactListener = nullptr;
void CollisionManager::Init() {
m_contactListener = EventListenerPhysicsContact::create();
m_contactListener->onContactBegin = [](PhysicsContact &contact) { return ContactBeginCallback(contact); };
m_contactListener->onContactSeparate = [](PhysicsContact &contact) { return ContactSeparateCallback(contact); };
}
bool CollisionManager::ContactBeginCallback(PhysicsContact &contact) {
PhysicsBody *_bodyA = contact.getShapeA()->getBody();
PhysicsBody *_bodyB = contact.getShapeB()->getBody();
const bool visionAndWallCondition = ((_bodyA->getCategoryBitmask() == vision_zone_collision_bitmask &&
_bodyB->getCategoryBitmask() == map_collision_bitmask) ||
(_bodyB->getCategoryBitmask() == vision_zone_collision_bitmask &&
_bodyA->getCategoryBitmask() == map_collision_bitmask));
if (visionAndWallCondition) {
for (Vec2 _p: contact.getContactData()->points) VisionZone::sm_shapeCollisionPoints.push_back(_p);
return true;
}
return false;
}
bool CollisionManager::ContactSeparateCallback(PhysicsContact &contact) {
PhysicsBody *_bodyA = contact.getShapeA()->getBody();
PhysicsBody *_bodyB = contact.getShapeB()->getBody();
const bool visionAndWallCondition = ((_bodyA->getCategoryBitmask() == vision_zone_collision_bitmask &&
_bodyB->getCategoryBitmask() == map_collision_bitmask) ||
(_bodyB->getCategoryBitmask() == vision_zone_collision_bitmask &&
_bodyA->getCategoryBitmask() == map_collision_bitmask));
if (visionAndWallCondition) {
VisionZone::sm_shapeCollisionPoints.clear();
return true;
}
return false;
}
GameLayer.cpp
bool GameLayer::init() {
if (!Layer::init()) return false;
CollisionManager::Init();
_eventDispatcher->addEventListenerWithSceneGraphPriority(CollisionManager::GetContactListener(), this);
// ... SOME CODE ... //
m_visionZone = VisionZone::create(player->getPosition(), 100);
addChild(m_visionZone, 1);
return true;
}
void GameLayer::update(float delta) {
Node::update(delta);
m_visionZone->UpdateWithPlayer(m_player->getPosition());
}
I am not sure about this method though ... I feels like it is not optimal at all ?
Really curious to have some feedback on this, thanks in advance, sorry for the quantity of code :)
Let me know if you need more informations, code or links
So, I'm trying to build my own game engine and my first project is creating a pacman clone. I've worked out how to create the tilemap and move pacman around on it. But I've having issues creating a collision detector with the tilemap. Particularly the issue is that the collision detects fine for any tiles north of the current location, however it thinks the tile below the current location is actually 1 tile larger than normal. And 0 collision exists for tiles east and west of the current location. I'm confused because the collision works for the north tile... but I'm using the same logic for the other directions and it's not working.
The logic I am using is that 'okay' tiles to move into are value 0. Any other tile is not able for movement.
Here is the code I'm using for the actual wall collision:
//checks for a sprite colliding with a wall tile
//direction refers to 1=North, 2=South, 3=West, 4=East
bool Wall_Collision(SPRITE sprite, int direction)
{
//grab center of sprite
Posx = sprite.x + Sprite_Radius;
Posy = sprite.y + Sprite_Radius;
//create rectangle for the sprite
RECT spriteRect;
spriteRect.left = (long)sprite.x;
spriteRect.top = (long)sprite.y;
spriteRect.right = (long)sprite.x + sprite.width * sprite.scaling;
spriteRect.bottom = (long)sprite.y + sprite.height * sprite.scaling;
//recover North tile info
int N_posx, N_posy;
int N_tilex, N_tiley;
int N_tilevalue;
N_posx = Posx / TILEWIDTH;
N_posy = (Posy - TILEHEIGHT) / TILEHEIGHT;
N_tilex = N_posx * TILEWIDTH;
N_tiley = N_posy * TILEHEIGHT;
N_tilevalue = MAPDATA[(N_posy * MAPWIDTH + N_posx)];
//create rectangle for tile North of sprite center
RECT northRect;
northRect.left = N_tilex;
northRect.top = N_tiley;
northRect.right = N_tilex + TILEWIDTH;
northRect.bottom = N_tiley + TILEHEIGHT;
//recover South tile info
int S_posx, S_posy;
int S_tilex, S_tiley;
int S_tilevalue;
S_posx = Posx / TILEWIDTH;
S_posy = (Posy + TILEHEIGHT) / TILEHEIGHT;
S_tilex = S_posx * TILEWIDTH;
S_tiley = S_posy * TILEHEIGHT;
S_tilevalue = MAPDATA[(S_posy * MAPWIDTH + S_posx)];
//create rectangle for tile South of sprite center
RECT southRect;
southRect.left = S_tilex;
southRect.top = S_tiley;
southRect.right = S_tilex + TILEWIDTH;
southRect.bottom = S_tiley + TILEHEIGHT;
//recover West tile info
int W_posx, W_posy;
int W_tilex, W_tiley;
int W_tilevalue;
W_posx = (Posx - TILEWIDTH) / TILEWIDTH;
W_posy = Posy / TILEHEIGHT;
W_tilex = W_posx * TILEWIDTH;
W_tiley = W_posy * TILEHEIGHT;
W_tilevalue = MAPDATA[(W_posy * MAPWIDTH + W_posx)];
//create rectangle for tile West of sprite center
RECT westRect;
westRect.left = W_tilex;
westRect.top = W_tiley;
westRect.right = W_tilex + TILEWIDTH;
westRect.bottom = W_tiley + TILEHEIGHT;
//recover East tile info
int E_posx, E_posy;
int E_tilex, E_tiley;
int E_tilevalue;
E_posx = (Posx + TILEWIDTH) / TILEWIDTH;
E_posy = Posy / TILEHEIGHT;
E_tilex = E_posx * TILEWIDTH;
E_tiley = E_posy * TILEHEIGHT;
E_tilevalue = MAPDATA[(E_posy * MAPWIDTH + E_posx)];
//create rectangle for tile East of sprite center
RECT eastRect;
eastRect.left = E_tilex;
eastRect.top = E_tiley;
eastRect.right = E_tilex + TILEWIDTH;
eastRect.bottom = E_tiley + TILEHEIGHT;
RECT dest; //ignored
//check North collision
if (direction == 1 && N_tilevalue != 0)
{
return IntersectRect(&dest, &spriteRect, &northRect);
}
else return false;
//check South collision
if (direction == 2 && S_tilevalue != 0)
{
return IntersectRect(&dest, &spriteRect, &southRect);
}
else return false;
//check West collision
if (direction == 3 && W_tilevalue != 0)
{
return IntersectRect(&dest, &spriteRect, &westRect);
}
else return false;
//check East collision
if (direction == 4 && E_tilevalue != 0)
{
return IntersectRect(&dest, &spriteRect, &eastRect);
}
else return false;
}
And then the context I'm using the function to move the player sprite:
void MovePacman()
{
if (Wall_Collision(pacman, 1))
{
pacman.y -= pacman.vely;
pacman.vely = 0.0f;
}
else
{
if (Key_Down(DIK_UP))
{
pacman.vely = -0.2f;
pacman.velx = 0.0f;
}
}
if (Wall_Collision(pacman, 2))
{
pacman.y -= pacman.vely;
pacman.vely = 0.0f;
}
else
{
if (Key_Down(DIK_DOWN))
{
pacman.vely = 0.2f;
pacman.velx = 0.0f;
}
}
if (Wall_Collision(pacman, 3))
{
pacman.x -= pacman.velx;
pacman.velx = 0.0f;
}
else
{
if (Key_Down(DIK_LEFT))
{
pacman.velx = -0.2f;
pacman.vely = 0.0f;
}
}
if (Wall_Collision(pacman, 4))
{
pacman.x -= pacman.velx;
pacman.velx = 0.0f;
}
else
{
if (Key_Down(DIK_RIGHT))
{
pacman.velx = 0.2f;
pacman.vely = 0.0f;
}
else;
}
if (pacman.vely < 0)
Sprite_Animate(pacman.frame, pacman.startframe, 18, 4, pacman.starttime, 250);
else if (pacman.vely > 0)
Sprite_Animate(pacman.frame, pacman.startframe, 16, 2, pacman.starttime, 250);
else if (pacman.velx < 0)
Sprite_Animate(pacman.frame, pacman.startframe, 17, 3, pacman.starttime, 250);
else if (pacman.velx > 0)
Sprite_Animate(pacman.frame, pacman.startframe, 15, 1, pacman.starttime, 250);
pacman.y += pacman.vely;
pacman.x += pacman.velx;
}
trust that I've defined everything that is not pasted and linked headers correctly. Any ideas where I'm going wrong?
You're only checking for collisions in one case:
//check North collision
if (direction == 1 && N_tilevalue != 0)
{
return IntersectRect(&dest, &spriteRect, &northRect);
}
else return false; // <--- this
//check South collision
if (direction == 2 && S_tilevalue != 0)
{
return IntersectRect(&dest, &spriteRect, &southRect);
}
else return false; // <--- and this, etc...
See the line highlighted above. If it doesn't test for a North collision (i.e. if direction isn't 1 or N_tilevalue is 0) then the function returns at that point in all other cases. It can never go on to do the other collision checks.
I currently have a OpenGL sprite drawing class that buffers up a bunch of sprite data then dumps it with glDrawElements. The problem is, creating the sprites that go into the buffer is cumbersome as I have loads of parameters to pass into the buffer with even more redundancy for the shaders. I was wondering if I could reduce CPU load by only loading the buffer with the essentials, location, orientation, texture coordinates etc... and then let a geometry shader turn that nonsense into quads for the fragment shader.
If theres a different answer, I've added the offending method so you can see what I mean:
void Machine::draw(key num, BoundingBox loc, float angle){
SpriteSyncData* props;
VertexAttribArray* vdata;
GLushort* idata;
SpriteProperties* sprite_props;
int sliceW;
int sliceH;
sprite_props = &spriteList[num];
props = &spriteToSync[sprite_props->atlas];
props->size++;
if(props->size > props->capacity){
props->capacity += COARSE_MEM_SCALE;
props->data = (VertexAttribArray*) realloc((void*) props->data, (sizeof(VertexAttribArray)*4) * props->capacity);
props->i_data = (GLushort*) realloc((void*) props->i_data, (sizeof(GLushort)*4) * props->capacity);
}
vdata = props->data + (props->size - 1) * 4;
idata = props->i_data + (props->size - 1) * 4;
sliceW = sprite_props->location.x1 - sprite_props->location.x0;
sliceH = sprite_props->location.y1 - sprite_props->location.y0;
if(sprite_props->flags & DRAW_TILED){
vdata[0].p = QVector3D(loc.x1, loc.y0, UNIFORM_DEPTH);
vdata[1].p = QVector3D(loc.x0, loc.y0, UNIFORM_DEPTH);
vdata[2].p = QVector3D(loc.x0, loc.y1, UNIFORM_DEPTH);
vdata[3].p = QVector3D(loc.x1, loc.y1, UNIFORM_DEPTH);
vdata[0].s = QVector2D(((float) (loc.x1 - loc.x0)) / sliceW,
((float) (loc.y1 - loc.y0)) / sliceH);
vdata[0].r = QVector2D(0, 0);
vdata[1].r = vdata[0].r;
vdata[2].r = vdata[0].r;
vdata[3].r = vdata[0].r;
}
else{
vdata[0].p = QVector3D(loc.x0 + sliceW, loc.y0, UNIFORM_DEPTH);
vdata[1].p = QVector3D(loc.x0, loc.y0, UNIFORM_DEPTH);
vdata[2].p = QVector3D(loc.x0, loc.y0 + sliceH, UNIFORM_DEPTH);
vdata[3].p = QVector3D(loc.x0 + sliceW, loc.y0 + sliceH, UNIFORM_DEPTH);
vdata[0].s = QVector2D(1, 1);
vdata[0].r = QVector2D(sliceW, sliceH);
vdata[1].r = vdata[0].r;
vdata[2].r = vdata[0].r;
vdata[3].r = vdata[0].r;
}
vdata[0].t = QVector2D(sprite_props->texCoords[2], sprite_props->texCoords[1]);
vdata[1].t = QVector2D(sprite_props->texCoords[0], sprite_props->texCoords[1]);
vdata[2].t = QVector2D(sprite_props->texCoords[0], sprite_props->texCoords[3]);
vdata[3].t = QVector2D(sprite_props->texCoords[2], sprite_props->texCoords[3]);
vdata[1].s = vdata[0].s;
vdata[2].s = vdata[0].s;
vdata[3].s = vdata[0].s;
vdata[0].s_lo = QVector2D(sprite_props->texCoords[0], sprite_props->texCoords[1]);
vdata[0].s_hi = QVector2D(sprite_props->texCoords[2] - sprite_props->texCoords[0],
sprite_props->texCoords[3] - sprite_props->texCoords[1]);
vdata[1].s_lo = vdata[0].s_lo;
vdata[1].s_hi = vdata[0].s_hi;
vdata[2].s_lo = vdata[0].s_lo;
vdata[2].s_hi = vdata[0].s_hi;
vdata[3].s_lo = vdata[0].s_lo;
vdata[3].s_hi = vdata[0].s_hi;
vdata[0].o = (vdata[1].p + vdata[3].p) * 0.5;
vdata[1].o = vdata[0].o;
vdata[2].o = vdata[0].o;
vdata[3].o = vdata[0].o;
vdata[0].a = angle;
vdata[1].a = angle;
vdata[2].a = angle;
vdata[3].a = angle;
idata[0] = (props->size - 1) * 4;
idata[1] = idata[0] + 1;
idata[2] = idata[0] + 2;
idata[3] = idata[0] + 3;
}
I am new to 3d programming so here goes. I am trying to simulate a room. I don't have images for the walls loaded but I want to in code simulate the boundaries. How do I accomplish this please?
Below is the code that handles the movement of the camera
bool calcMovement()
{
// return if less then two events have been added.
if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false;
//calcIntersect();
double dt = _ga_t0->getTime()-_ga_t1->getTime();
if (dt<0.0f)
{
OSG_INFO << "warning dt = "<<dt<< std::endl;
dt = 0.0;
}
double accelerationFactor = _height*10.0;
switch(_speedMode)
{
case(USE_MOUSE_Y_FOR_SPEED):
{
double dy = _ga_t0->getYnormalized();
_velocity = _height*dy;
break;
}
case(USE_MOUSE_BUTTONS_FOR_SPEED):
{
unsigned int buttonMask = _ga_t1->getButtonMask();
//add cases here for finding which key was pressed.
if (buttonMask==GUIEventAdapter::LEFT_MOUSE_BUTTON || wPressed)
{
// pan model.
_velocity += dt*accelerationFactor;
}
else if (buttonMask==GUIEventAdapter::MIDDLE_MOUSE_BUTTON ||
buttonMask==(GUIEventAdapter::LEFT_MOUSE_BUTTON|GUIEventAdapter::RIGHT_MOUSE_BUTTON))
{
_velocity = 0.0;
}
else if (buttonMask==GUIEventAdapter::RIGHT_MOUSE_BUTTON || sPressed)
{
_velocity -= dt*accelerationFactor;
}
break;
}
}
osg::CoordinateFrame cf=getCoordinateFrame(_eye);
osg::Matrixd rotation_matrix;
rotation_matrix.makeRotate(_rotation);
osg::Vec3d up = osg::Vec3d(0.0,1.0,0.0) * rotation_matrix;
osg::Vec3d lv = osg::Vec3d(0.0,0.0,-1.0) * rotation_matrix;
osg::Vec3d sv = osg::Vec3d(1.0,0.0,0.0) * rotation_matrix;
// rotate the camera.
double dx = _ga_t0->getXnormalized();
double yaw = -inDegrees(dx*50.0*dt);
#ifdef KEYBOARD_PITCH
double pitch_delta = 0.5;
if (_pitchUpKeyPressed) _pitch += pitch_delta*dt;
if (_pitchDownKeyPressed) _pitch -= pitch_delta*dt;
#endif
#if defined(ABOSULTE_PITCH)
// absolute pitch
double dy = _ga_t0->getYnormalized();
_pitch = -dy*0.5;
#elif defined(INCREMENTAL_PITCH)
// incremental pitch
double dy = _ga_t0->getYnormalized();
_pitch += dy*dt;
#endif
osg::Quat yaw_rotation;
yaw_rotation.makeRotate(yaw,up);
_rotation *= yaw_rotation;
rotation_matrix.makeRotate(_rotation);
sv = osg::Vec3d(1.0,0.0,0.0) * rotation_matrix;
wPressed = false;
sPressed = false;
// movement is big enough the move the eye point along the look vector.
if (fabs(_velocity*dt)>1e-8)
{
double distanceToMove = _velocity*dt;
double signedBuffer;
if (distanceToMove>=0.0) signedBuffer=_buffer;
else signedBuffer=-_buffer;
// check to see if any obstruction in front.
osg::Vec3d ip, np;
if (intersect(_eye,_eye+lv*(signedBuffer+distanceToMove), ip, np))
{
if (distanceToMove>=0.0)
{
distanceToMove = (ip-_eye).length()-_buffer;
}
else
{
distanceToMove = _buffer-(ip-_eye).length();
}
_velocity = 0.0;
}
// check to see if forward point is correct height above terrain.
osg::Vec3d fp = _eye + lv*distanceToMove;
osg::Vec3d lfp = fp - up*(_height*5.0);
if (intersect(fp, lfp, ip, np))
{
if (up*np>0.0) up = np;
else up = -np;
_eye = ip+up*_height;
lv = up^sv;
computePosition(_eye,_eye+lv,up);
return true;
}
// no hit on the terrain found therefore resort to a fall under
// under the influence of gravity.
osg::Vec3d dp = lfp;
dp -= getUpVector(cf)* (2.0*_modelScale);
if (intersect(lfp, dp, ip, np))
{
if (up*np>0.0) up = np;
else up = -np;
_eye = ip+up*_height;
lv = up^sv;
computePosition(_eye,_eye+lv,up);
return true;
}
// no collision with terrain has been found therefore track horizontally.
lv *= (_velocity*dt);
_eye += lv;
}
return true;
}
I have written some code to preform 3D picking that for some reason dosn't work entirely correct! (Im using LWJGL just so you know.)
This is how the code looks like:
if(Mouse.getEventButton() == 1) {
if (!Mouse.getEventButtonState()) {
Camera.get().generateViewMatrix();
float screenSpaceX = ((Mouse.getX()/800f/2f)-1.0f)*Camera.get().getAspectRatio();
float screenSpaceY = 1.0f-(2*((600-Mouse.getY())/600f));
float displacementRate = (float)Math.tan(Camera.get().getFovy()/2);
screenSpaceX *= displacementRate;
screenSpaceY *= displacementRate;
Vector4f cameraSpaceNear = new Vector4f((float) (screenSpaceX * Camera.get().getNear()), (float) (screenSpaceY * Camera.get().getNear()), (float) (-Camera.get().getNear()), 1);
Vector4f cameraSpaceFar = new Vector4f((float) (screenSpaceX * Camera.get().getFar()), (float) (screenSpaceY * Camera.get().getFar()), (float) (-Camera.get().getFar()), 1);
Matrix4f tmpView = new Matrix4f();
Camera.get().getViewMatrix().transpose(tmpView);
Matrix4f invertedViewMatrix = (Matrix4f)tmpView.invert();
Vector4f worldSpaceNear = new Vector4f();
Matrix4f.transform(invertedViewMatrix, cameraSpaceNear, worldSpaceNear);
Vector4f worldSpaceFar = new Vector4f();
Matrix4f.transform(invertedViewMatrix, cameraSpaceFar, worldSpaceFar);
Vector3f rayPosition = new Vector3f(worldSpaceNear.x, worldSpaceNear.y, worldSpaceNear.z);
Vector3f rayDirection = new Vector3f(worldSpaceFar.x - worldSpaceNear.x, worldSpaceFar.y - worldSpaceNear.y, worldSpaceFar.z - worldSpaceNear.z);
rayDirection.normalise();
Ray clickRay = new Ray(rayPosition, rayDirection);
Vector tMin = new Vector(), tMax = new Vector(), tempPoint;
float largestEnteringValue, smallestExitingValue, temp, closestEnteringValue = Camera.get().getFar()+0.1f;
Drawable closestDrawableHit = null;
for(Drawable d : this.worldModel.getDrawableThings()) {
// Calcualte AABB for each object... needs to be moved later...
firstVertex = true;
for(Surface surface : d.getSurfaces()) {
for(Vertex v : surface.getVertices()) {
worldPosition.x = (v.x+d.getPosition().x)*d.getScale().x;
worldPosition.y = (v.y+d.getPosition().y)*d.getScale().y;
worldPosition.z = (v.z+d.getPosition().z)*d.getScale().z;
worldPosition = worldPosition.rotate(d.getRotation());
if (firstVertex) {
maxX = worldPosition.x; maxY = worldPosition.y; maxZ = worldPosition.z;
minX = worldPosition.x; minY = worldPosition.y; minZ = worldPosition.z;
firstVertex = false;
} else {
if (worldPosition.x > maxX) {
maxX = worldPosition.x;
}
if (worldPosition.x < minX) {
minX = worldPosition.x;
}
if (worldPosition.y > maxY) {
maxY = worldPosition.y;
}
if (worldPosition.y < minY) {
minY = worldPosition.y;
}
if (worldPosition.z > maxZ) {
maxZ = worldPosition.z;
}
if (worldPosition.z < minZ) {
minZ = worldPosition.z;
}
}
}
}
// ray/slabs intersection test...
// clickRay.getOrigin().x + clickRay.getDirection().x * f = minX
// clickRay.getOrigin().x - minX = -clickRay.getDirection().x * f
// clickRay.getOrigin().x/-clickRay.getDirection().x - minX/-clickRay.getDirection().x = f
// -clickRay.getOrigin().x/clickRay.getDirection().x + minX/clickRay.getDirection().x = f
largestEnteringValue = -clickRay.getOrigin().x/clickRay.getDirection().x + minX/clickRay.getDirection().x;
temp = -clickRay.getOrigin().y/clickRay.getDirection().y + minY/clickRay.getDirection().y;
if(largestEnteringValue < temp) {
largestEnteringValue = temp;
}
temp = -clickRay.getOrigin().z/clickRay.getDirection().z + minZ/clickRay.getDirection().z;
if(largestEnteringValue < temp) {
largestEnteringValue = temp;
}
smallestExitingValue = -clickRay.getOrigin().x/clickRay.getDirection().x + maxX/clickRay.getDirection().x;
temp = -clickRay.getOrigin().y/clickRay.getDirection().y + maxY/clickRay.getDirection().y;
if(smallestExitingValue > temp) {
smallestExitingValue = temp;
}
temp = -clickRay.getOrigin().z/clickRay.getDirection().z + maxZ/clickRay.getDirection().z;
if(smallestExitingValue < temp) {
smallestExitingValue = temp;
}
if(largestEnteringValue > smallestExitingValue) {
//System.out.println("Miss!");
} else {
if (largestEnteringValue < closestEnteringValue) {
closestEnteringValue = largestEnteringValue;
closestDrawableHit = d;
}
}
}
if(closestDrawableHit != null) {
System.out.println("Hit at: (" + clickRay.setDistance(closestEnteringValue).x + ", " + clickRay.getCurrentPosition().y + ", " + clickRay.getCurrentPosition().z);
this.worldModel.removeDrawableThing(closestDrawableHit);
}
}
}
I just don't understand what's wrong, the ray are shooting and i do hit stuff that gets removed but the result of the ray are verry strange it sometimes removes the thing im clicking at, sometimes it removes things thats not even close to what im clicking at, and sometimes it removes nothing at all.
Edit:
Okay so i have continued searching for errors and by debugging the ray (by painting smal dots where it travles) i can now se that there is something oviously wrong with the ray that im sending out... it has its origin near the world center and always shots to the same position no matter where i direct my camera...
My initial toughts is that there might be some error in the way i calculate my viewMatrix (since it's not possible to get the viewmatrix from the glulookat method in lwjgl; I have to build it my self and I guess thats where the problem is at)...
Edit2:
This is how i calculate it currently:
private double[][] viewMatrixDouble = {{0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,1}};
public Vector getCameraDirectionVector() {
Vector actualEye = this.getActualEyePosition();
return new Vector(lookAt.x-actualEye.x, lookAt.y-actualEye.y, lookAt.z-actualEye.z);
}
public Vector getActualEyePosition() {
return eye.rotate(this.getRotation());
}
public void generateViewMatrix() {
Vector cameraDirectionVector = getCameraDirectionVector().normalize();
Vector side = Vector.cross(cameraDirectionVector, this.upVector).normalize();
Vector up = Vector.cross(side, cameraDirectionVector);
viewMatrixDouble[0][0] = side.x; viewMatrixDouble[0][1] = up.x; viewMatrixDouble[0][2] = -cameraDirectionVector.x;
viewMatrixDouble[1][0] = side.y; viewMatrixDouble[1][1] = up.y; viewMatrixDouble[1][2] = -cameraDirectionVector.y;
viewMatrixDouble[2][0] = side.z; viewMatrixDouble[2][1] = up.z; viewMatrixDouble[2][2] = -cameraDirectionVector.z;
/*
Vector actualEyePosition = this.getActualEyePosition();
Vector zaxis = new Vector(this.lookAt.x - actualEyePosition.x, this.lookAt.y - actualEyePosition.y, this.lookAt.z - actualEyePosition.z).normalize();
Vector xaxis = Vector.cross(upVector, zaxis).normalize();
Vector yaxis = Vector.cross(zaxis, xaxis);
viewMatrixDouble[0][0] = xaxis.x; viewMatrixDouble[0][1] = yaxis.x; viewMatrixDouble[0][2] = zaxis.x;
viewMatrixDouble[1][0] = xaxis.y; viewMatrixDouble[1][1] = yaxis.y; viewMatrixDouble[1][2] = zaxis.y;
viewMatrixDouble[2][0] = xaxis.z; viewMatrixDouble[2][1] = yaxis.z; viewMatrixDouble[2][2] = zaxis.z;
viewMatrixDouble[3][0] = -Vector.dot(xaxis, actualEyePosition); viewMatrixDouble[3][1] =-Vector.dot(yaxis, actualEyePosition); viewMatrixDouble[3][2] = -Vector.dot(zaxis, actualEyePosition);
*/
viewMatrix = new Matrix4f();
viewMatrix.load(getViewMatrixAsFloatBuffer());
}
Would be verry greatfull if anyone could verify if this is wrong or right, and if it's wrong; supply me with the right way of doing it...
I have read alot of threads and documentations about this but i can't seam to wrapp my head around it...
I just don't understand what's wrong, the ray are shooting and i do hit stuff that gets removed but things are not disappearing where i press on the screen.
OpenGL is not a scene graph, it's a drawing library. So after removing something from your internal representation you must redraw the scene. And your code is missing some call to a function that triggers a redraw.
Okay so i finaly solved it with the help from the guys at gamedev and a friend, here is a link to the answer where i have posted the code!