onut::Entity* LevelGenerator::createRoom(int startX, int startY, const sRoom& room) { auto pRoomEntity = new onut::Entity(); pRoomEntity->setPosition({static_cast<float>(startX), static_cast<float>(startY), 0.f}); // Create floor. 5x5 for (int y = 0; y < room.h; ++y) { for (int x = 0; x < room.w; ++x) { const auto& tileId = room.tiles[(room.h - y - 1) * room.w * 2 + x * 2]; const auto& modifier = room.tiles[(room.h - y - 1) * room.w * 2 + x * 2 + 1]; onut::Entity* pEntity = nullptr; // Solid if (isWall(tileId)) { pEntity = onut::EntityFactory::createMesh({static_cast<float>(x), static_cast<float>(y), 0.f}, "assets/meshes/wall1.mesh", "assets/materials/wall1.material"); } else if (isFloor(tileId)) { if (onut::randb(.04f)) { pEntity = onut::EntityFactory::createMesh({static_cast<float>(x), static_cast<float>(y), 0.f}, "assets/meshes/floor2.mesh", "assets/materials/floor2.material"); } else { pEntity = onut::EntityFactory::createMesh({static_cast<float>(x), static_cast<float>(y), 0.f}, "assets/meshes/floor.mesh", "assets/materials/floor.material"); } } // Addons if (pEntity) { if (isTorch(tileId) && onut::randb(.85f)) { pEntity->add(createTorch({0.f, 0.75f})); } pEntity->setRotation({0, 0, getAngle(modifier)}); } pRoomEntity->add(pEntity); } } return pRoomEntity; }
//flood fills some muck starting at x,y int shMapLevel::floodMuck (int sx, int sy, shTerrainType type, int amount) { int x, y, i; shDirection dirs[4] = { kNorth, kSouth, kEast, kWest }; shDirection dir; int n = 0; shVector <int> points; points.add (xytop (sx, sy)); for (n = 0; n < amount;) { int p; if (0 == points.count ()) { return n; } p = points.removeByIndex (RNG (points.count ())); x = ptox (p); y = ptoy (p); if (!isFloor (x, y) or kSewage == getSquare (x, y) ->mTerr) { continue; } n++; if (RNG(2)) SETSQ (x, y, kSewage); for (i = 0; i < 4; i++) { dir = dirs[i]; int x2 = x; int y2 = y; if (moveForward (dir, &x2, &y2) and RNG (20) >= points.count ()) { points.add (xytop (x2, y2)); } } } return n; }
void LVL_Player::_collideUnduck() { _syncPosition(); if(isWarping) return; #ifdef COLLIDE_DEBUG qDebug() << "do unduck!"; #endif //Detect collidable blocks! QVector<PGE_Phys_Object*> bodies; PGE_RectF posRectC = posRect; posRectC.setTop(posRectC.top()-4.0f); posRectC.setLeft(posRectC.left()+1.0f); posRectC.setRight(posRectC.right()-1.0f); posRectC.setBottom(posRectC.bottom()+ (ducking ? 0.0:(-posRect.height()/2.0))+4.0 ); LvlSceneP::s->queryItems(posRectC, &bodies); forceCollideCenter=true; for(PGE_RenderList::iterator it=bodies.begin();it!=bodies.end(); it++ ) { PGE_Phys_Object*body=*it; if(body==this) continue; if(body->isPaused()) continue; if(!body->isVisible()) continue; solveCollision(body); } forceCollideCenter=false; #ifdef COLLIDE_DEBUG int hited=0; PGE_RectF nearestRect; #endif bool resolveTop=false; double _floorY=0; QVector<PGE_Phys_Object*> blocks_to_hit; if((!collided_center.isEmpty())&&(collided_bottom.isEmpty())) { for(PlayerColliders::iterator it=collided_center.begin(); it!=collided_center.end() ; it++) { PGE_Phys_Object *collided= *it; LVL_Block *blk= static_cast<LVL_Block*>(collided); if(blk) blocks_to_hit.push_back(blk); } for(PlayerColliders::iterator it=collided_top.begin(); it!=collided_top.end() ; it++) { PGE_Phys_Object *collided= *it; LVL_Block *blk= static_cast<LVL_Block*>(collided); if(blk) blocks_to_hit.push_back(blk); } if(isFloor(blocks_to_hit)) { PGE_Phys_Object*nearest = nearestBlockY(blocks_to_hit); if(nearest) { _floorY=nearest->posRect.bottom()+1.0; resolveTop=true; } } } if(resolveTop) { posRect.setY(_floorY); if(!blocks_to_hit.isEmpty()) { PGE_Phys_Object*nearest_obj=nearestBlock(blocks_to_hit); if(nearest_obj && (nearest_obj->type==PGE_Phys_Object::LVLBlock)) { LVL_Block*nearest = static_cast<LVL_Block*>(nearest_obj); resolveTop=true; long npcid=nearest->data.npc_id; nearest->hit(); if( nearest->setup->hitable || (npcid!=0) || (nearest->destroyed) || (nearest->setup->bounce) ) { bump(false, speedY()); } } else { PGE_Audio::playSoundByRole(obj_sound_role::BlockHit); } } setSpeedY(0.0); _syncPosition(); } _heightDelta = 0.0; #ifdef COLLIDE_DEBUG qDebug() << "unduck: blocks to hit"<< hited << " Nearest: "<<nearestRect.top() << nearestRect.bottom() << "are bottom empty: " << collided_bottom.isEmpty() << "bodies found: "<<bodies.size() << "bodies at center: "<<collided_center.size(); #endif }
void LVL_Player::updateCollisions() { foot_contacts_map.clear(); _onGround=false; foot_sl_contacts_map.clear(); contactedWarp = NULL; contactedWithWarp=false; climbable_map.clear(); environments_map.clear(); collided_top.clear(); collided_left.clear(); collided_right.clear(); collided_bottom.clear(); collided_center.clear(); collided_talkable_npc = NULL; collided_slope=false; collided_slope_direct=0; collided_slope_angle_ratio=0.0f; _velocityX_add=0; _velocityY_add=0; #ifdef COLLIDE_DEBUG qDebug() << "=====Collision check and resolve begin======"; #endif PGE_Phys_Object::updateCollisions(); bool resolveBottom=false; bool resolveTop=false; bool resolveLeft=false; bool resolveRight=false; double backupX=posRect.x(); double backupY=posRect.y(); double _wallX=posRect.x(); double _floorY=posRect.y(); double _floorX_vel=0.0;//velocities sum double _floorX_num=0.0;//num of velocities double _floorY_vel=0.0;//velocities sum double _floorY_num=0.0;//num of velocities QVector<PGE_Phys_Object*> floor_blocks; QVector<PGE_Phys_Object*> wall_blocks; QVector<PGE_Phys_Object*> blocks_to_hit; //QVector<PGE_Phys_Object*> add_speed_to; if(!collided_bottom.isEmpty()) { for(PlayerColliders::iterator it=collided_bottom.begin(); it!=collided_bottom.end() ; it++) { PGE_Phys_Object *collided= *it; switch(collided->type) { case PGE_Phys_Object::LVLBlock: { LVL_Block *blk= static_cast<LVL_Block*>(collided); if(!blk) continue; foot_contacts_map[(intptr_t)collided]=collided; if(blk->slippery_surface) foot_sl_contacts_map[(intptr_t)collided]=collided; if(blk->setup->bounce) blocks_to_hit.push_back(blk); floor_blocks.push_back(blk); _floorY_vel+=blk->speedYsum(); _floorY_num+=1.0; _floorX_vel+=blk->speedXsum(); _floorX_num+=1.0; } break; case PGE_Phys_Object::LVLNPC: { LVL_Npc *npc= static_cast<LVL_Npc*>(collided); if(!npc) continue; foot_contacts_map[(intptr_t)collided]=collided; if(npc->slippery_surface) foot_sl_contacts_map[(intptr_t)collided]=collided; floor_blocks.push_back(npc); _floorY_vel+=npc->speedYsum(); _floorY_num+=1.0; _floorX_vel+=npc->speedXsum(); _floorX_num+=1.0; } break; default:break; } } if(_floorX_num!=0.0) _floorX_vel=_floorX_vel/_floorX_num; if(_floorY_num!=0.0) _floorY_vel=_floorY_vel/_floorY_num; if(!foot_contacts_map.isEmpty()) { _velocityX_add=_floorX_vel; _velocityY_add=_floorY_vel; } if(isFloor(floor_blocks)) { PGE_Phys_Object*nearest = nearestBlockY(floor_blocks); if(nearest) { LVL_Block *blk= static_cast<LVL_Block*>(nearest); if(blk && (blk->shape!=LVL_Block::shape_rect)) { if(blk->shape==LVL_Block::shape_tr_top_right) { _floorY = nearest->posRect.bottom()-SL_HeightTopRight(nearest); if(_floorY<nearest->top()) _floorY=nearest->posRect.top(); else if(_floorY>nearest->bottom()) _floorY=nearest->posRect.bottom(); } else if(blk->shape==LVL_Block::shape_tr_top_left) { _floorY = nearest->posRect.bottom()-SL_HeightTopLeft(nearest); if(_floorY<nearest->top()) _floorY=nearest->posRect.top(); else if(_floorY>nearest->bottom()) _floorY=nearest->posRect.bottom(); } else if(blk->shape==LVL_Block::shape_tr_bottom_right) { _floorY = nearest->posRect.top()+SL_HeightTopRight(nearest); if(_floorY<nearest->top()) _floorY=nearest->posRect.top(); else if(_floorY>nearest->bottom()) _floorY=nearest->posRect.bottom(); } else if(blk->shape==LVL_Block::shape_tr_bottom_left) { _floorY = nearest->posRect.top()+SL_HeightTopLeft(nearest); if(_floorY<nearest->top()) _floorY=nearest->posRect.top(); else if(_floorY>nearest->bottom()) _floorY=nearest->posRect.bottom(); } else _floorY = nearest->posRect.top(); _floorY-=posRect.height(); } else { _floorY = nearest->posRect.top()-posRect.height(); } resolveBottom=true; } } else { foot_contacts_map.clear(); foot_sl_contacts_map.clear(); } } if(!collided_top.isEmpty()) { blocks_to_hit.clear(); for(PlayerColliders::iterator it=collided_top.begin(); it!=collided_top.end() ; it++) { PGE_Phys_Object *body= *it; if(body) blocks_to_hit.push_back(body); if(body) floor_blocks.push_back(body); } if(isFloor(floor_blocks)) { PGE_Phys_Object*nearest = nearestBlockY(blocks_to_hit); if(nearest) { if(!resolveBottom) { LVL_Block *blk= static_cast<LVL_Block*>(nearest); if(blk && (blk->shape!=LVL_Block::shape_rect)) { if(blk->shape==LVL_Block::shape_tr_bottom_right) { _floorY = nearest->posRect.top()+SL_HeightTopLeft(nearest); if(_floorY<nearest->top()) _floorY=nearest->posRect.top(); else if(_floorY>nearest->bottom()) _floorY=nearest->posRect.bottom(); } else if(blk->shape==LVL_Block::shape_tr_bottom_left) { _floorY = nearest->posRect.top()+SL_HeightTopRight(nearest); if(_floorY<nearest->top()) _floorY=nearest->posRect.top(); else if(_floorY>nearest->bottom()) _floorY=nearest->posRect.bottom(); } } else _floorY = nearest->posRect.bottom(); _floorY+=1; } resolveTop=true; } } } bool wall=false; if(!collided_left.isEmpty()) { for(PlayerColliders::iterator it=collided_left.begin(); it!=collided_left.end() ; it++) { PGE_Phys_Object *body= *it; if(body) wall_blocks.push_back(body); } if(isWall(wall_blocks)) { PGE_Phys_Object*nearest = nearestBlock(wall_blocks); if(nearest) { _wallX = nearest->posRect.right(); resolveLeft=true; wall=true; } } } if(!collided_right.isEmpty()) { wall_blocks.clear(); for(PlayerColliders::iterator it=collided_right.begin(); it!=collided_right.end() ; it++) { PGE_Phys_Object *body= *it; if(body) wall_blocks.push_back(body); } if(isWall(wall_blocks)) { PGE_Phys_Object*nearest = nearestBlock(wall_blocks); if(nearest) { _wallX = nearest->posRect.left()-posRect.width(); resolveRight=true; wall=true; } } } if((resolveLeft||resolveRight) && (resolveTop||resolveBottom)) { //check if on floor or in air bool _iswall=false; bool _isfloor=false; posRect.setX(_wallX); _isfloor=isFloor(floor_blocks); posRect.setPos(backupX, _floorY); _iswall=isWall(wall_blocks); posRect.setX(backupX); if(!_iswall && _isfloor) { resolveLeft=false; resolveRight=false; } if(!_isfloor && _iswall) { resolveTop=false; resolveBottom=false; } } if(resolveLeft || resolveRight) { posRect.setX(_wallX); setSpeedX(0); _velocityX_add=0; } if(resolveBottom || resolveTop) { posRect.setY(_floorY); float bumpSpeed=speedY(); setSpeedY(_floorY_vel); _velocityY_add=0; if(!blocks_to_hit.isEmpty()) { PGE_Phys_Object* nearestObj=nearestBlock(blocks_to_hit); if(nearestObj && (nearestObj->type==PGE_Phys_Object::LVLBlock)) { LVL_Block*nearest = static_cast<LVL_Block*>(nearestObj); long npcid=nearest->data.npc_id; if(resolveBottom) nearest->hit(LVL_Block::down); else nearest->hit(); if( nearest->setup->hitable || (npcid!=0) || (nearest->destroyed) || nearest->setup->bounce ) bump(resolveBottom, (resolveBottom ? physics_cur.velocity_jump_bounce : bumpSpeed), physics_cur.jump_time_bounce); } else { PGE_Audio::playSoundByRole(obj_sound_role::BlockHit); } } if(resolveTop && !bumpUp && !bumpDown ) jumpTime=0; } else { posRect.setY(backupY); } _stucked = ( (!collided_center.isEmpty()) && (!collided_bottom.isEmpty()) && (!wall) ); #ifdef COLLIDE_DEBUG qDebug() << "=====Collision check and resolve end======"; #endif }