int main(int argc, char *argv[]) { Pooma::initialize(argc, argv); Pooma::Tester tester(argc, argv); Interval<1> n1(1,5); Interval<1> n2(4,8); Interval<1> n3(10,20); Interval<2> a(n1,n2); Interval<3> b(n1,n2,n3); Range<1> r1(1,5); Range<1> r2(4,8,2); Range<1> r3(5,9,2); Range<1> r4(10,20,5); Range<2> ra(r1,r2); Range<2> rb(r1,r3); Range<3> rc(r1,r2,r3); tester.out() << "1: touches(" << a[0] << "," << a[1] << ") ? "; tester.out() << touches(a[0], a[1]) << std::endl; tester.check( touches(a[0], a[1]) ); tester.out() << "0: touches(" << a[0] << "," << b[2] << ") ? "; tester.out() << touches(a[0], b[2]) << std::endl; tester.check( touches(a[0], b[2])==0); tester.out() << "1: touches(" << a[0] << "," << ra[0] << ") ? "; tester.out() << touches(a[0], ra[0]) << std::endl; tester.check(touches(a[0], ra[0])); tester.out() << "1: touches(" << ra[0] << "," << ra[1] << ") ? "; tester.out() << touches(ra[0], ra[1]) << std::endl; tester.check( touches(ra[0], ra[1])); tester.out() << "0: touches(" << r2 << "," << r3 << ") ? "; tester.out() << touches(r2, r3) << std::endl; tester.check( touches(r2, r3)==0); tester.out() << "0: touches(" << ra << "," << rb << ") ? "; tester.out() << touches(ra, rb) << std::endl; tester.check( touches(ra, rb) ==0); tester.out() << "1: touches(" << rc << "," << rc << ") ? "; tester.out() << touches(rc, rc) << std::endl; tester.check( touches(rc, rc) ); tester.out() << "------------------------------------" << std::endl; tester.check(" touches ", true); Interval<1> c1(1,10); Interval<1> c2(3,8); Interval<1> c3(5,15); Interval<2> ca(c1, c1); Interval<2> cb(c1, c2); Range<1> cr1(2,20,2); Range<1> cr2(4,16,4); Range<1> cr3(3,15,2); Range<1> cr4(5,15,5); tester.out() << "1: contains(" << c1 << "," << c2 << ") ? "; tester.out() << contains(c1,c2) << std::endl; tester.check(contains(c1,c2)); tester.out() << "0: contains(" << c2 << "," << c1 << ") ? "; tester.out() << contains(c2,c1) << std::endl; tester.check(contains(c2,c1)==0); tester.out() << "0: contains(" << c1 << "," << c3 << ") ? "; tester.out() << contains(c1,c3) << std::endl; tester.check(contains(c1,c3)==0); tester.out() << "1: contains(" << ca << "," << cb << ") ? "; tester.out() << contains(ca,cb) << std::endl; tester.check(contains(ca,cb)); tester.out() << "0: contains(" << cb << "," << ca << ") ? "; tester.out() << contains(cb,ca) << std::endl; tester.check(contains(cb,ca)==0); tester.out() << "1: contains(" << cr1 << "," << cr2 << ") ? "; tester.out() << contains(cr1,cr2) << std::endl; tester.check( contains(cr1,cr2)); tester.out() << "0: contains(" << cr1 << "," << cr3 << ") ? "; tester.out() << contains(cr1,cr3) << std::endl; tester.check(contains(cr1,cr3)==0); tester.out() << "1: contains(" << c3 << "," << cr4 << ") ? "; tester.out() << contains(c3,cr4) << std::endl; tester.check(contains(c3,cr4)); tester.out() << "0: contains(" << cr4 << "," << c3 << ") ? "; tester.out() << contains(cr4,c3) << std::endl; tester.check(contains(cr4,c3)==0); tester.out() << "------------------------------------" << std::endl; Interval<2> s1, s2; Range<2> sr1, sr2; split(cb, s1, s2); tester.out() << "split(" << cb << ") = " << s1 << " and " << s2 << std::endl; tester.check(s1==Interval<2>(Interval<1>(1,5),Interval<1>(3,5))); tester.check(s2==Interval<2>(Interval<1>(6,10),Interval<1>(6,8))); split(rb, sr1, sr2); tester.out() << "split(" << rb << ") = " << sr1 << " and " << sr2 << std::endl; tester.check(sr1==Range<2>(Range<1>(1,2),Range<1>(5,5,2))); tester.check(sr2==Range<2>(Range<1>(3,5),Range<1>(7,9,2))); tester.out() << "------------------------------------" << std::endl; tester.out() << "intersect(" << cb << "," << ca << ") = "; tester.out() << intersect(cb,ca) << std::endl; tester.check(intersect(cb,ca)==Interval<2>(Interval<1>(1,10), Interval<1>(3,8))); tester.out() << "intersect(" << rb << "," << ra << ") = "; tester.out() << intersect(rb,ra) << std::endl; Range<1> i1(1,16,3); Range<1> i2(17,3,-2); tester.out() << "intersect(" << i1 << "," << i2 << ") = "; tester.out() << intersect(i1,i2) << std::endl; tester.check( intersect(i1,i2) == Range<1>(7,14,6)); tester.out() << "intersect(" << i2 << "," << i1 << ") = "; tester.out() << intersect(i2,i1) << std::endl; tester.check( intersect(i2,i1) == Range<1>(13,7,-6)); tester.out() << "------------------------------------" << std::endl; Interval<1> eq1(1,5); Range<1> eq2 = -2 * eq1 + 3; Range<1> eq3(-8,8,4); Range<1> eq4 = 3 * eq1; Range<1> eq5 = 2 * eq1; Range<1> eq6 = 6 * eq1 + 1; tester.out() << "For " << eq1 << " --> " << eq4 << ", then " << eq3 << " --> "; tester.out() << equivSubset(eq1,eq4,eq3) << std::endl; tester.out() << "For " << eq4 << " --> " << eq6 << ", then " << eq3 << " --> "; tester.out() << equivSubset(eq4,eq6,eq3) << std::endl; tester.out() << "For " << eq1 << " --> " << eq2 << ", then " << eq3 << " --> "; tester.out() << equivSubset(eq1,eq2,eq3) << std::endl; tester.out() << "------------------------------------" << std::endl; NewDomain3<Interval<1>, Interval<1>, int>::SliceType_t ba; // tester.out() << "Created initial slice domain ba = " << ba << std::endl; ba = NewDomain3<Interval<1>, Interval<1>, int>::combineSlice(ba,eq1,eq1,7); tester.out() << "After taking slice, ba = " << ba << std::endl; int retval = tester.results("Domain Calc"); Pooma::finalize(); return retval; }
typename enable_if<is_interval_map<Type>, bool>::type is_joinable(typename Type::iterator it_, typename Type::iterator next_, Type* = 0) { return touches(it_->first, next_->first) && it_->second == next_->second ; }
Touch peakToTouch(Touch p) { return Touch{.x = mapRange(3.5f, 59.5f, 1.f, 29.f, p.x), .y = sensorToKeyY(p.y), .z = p.z}; } // quick touch finder based on peaks of curvature. // this works well, but a different approach based on blob sizes / shapes could do a much better // job with contiguous keys. TouchArray TouchTracker::findTouches(const SensorFrame& in) { constexpr int kMaxPeaks = kMaxTouches*2; constexpr int w = SensorGeometry::width; constexpr int h = SensorGeometry::height; const float* pIn = in.data(); int i, j; std::array<Touch, kMaxPeaks> peaks; TouchArray touches{}; std::array<std::bitset<w>, h> map; // get peaks float f11, f12, f13; float f21, f22, f23; float f31, f32, f33; j = 0; { auto& row = map[j]; const float* pRow2 = pIn + (j)*w; const float* pRow3 = pIn + (j + 1)*w; for(i = 1; i < w - 1; ++i) { f21 = pRow2[i - 1]; f22 = pRow2[i]; f23 = pRow2[i + 1]; f31 = pRow3[i - 1]; f32 = pRow3[i]; f33 = pRow3[1 + 1]; row[i] = (f22 > f21) && (f22 > mFilterThreshold) && (f22 > f23) && (f22 > f31) && (f22 > f32) && (f22 > f33); } } for (j = 1; j < h - 1; ++j) { auto& row = map[j]; const float* pRow1 = pIn + (j - 1)*w; const float* pRow2 = pIn + (j)*w; const float* pRow3 = pIn + (j + 1)*w; for(i = 1; i < w - 1; ++i) { f11 = pRow1[i - 1]; f12 = pRow1[i]; f13 = pRow1[i + 1]; f21 = pRow2[i - 1]; f22 = pRow2[i]; f23 = pRow2[i + 1]; f31 = pRow3[i - 1]; f32 = pRow3[i]; f33 = pRow3[1 + 1]; row[i] = (f22 > f11) && (f22 > f12) && (f22 > f13) && (f22 > f21) && (f22 > mFilterThreshold) && (f22 > f23) && (f22 > f31) && (f22 > f32) && (f22 > f33); } } j = h - 1; { auto& row = map[j]; const float* pRow1 = pIn + (j - 1)*w; const float* pRow2 = pIn + (j)*w; for(i = 1; i < w - 1; ++i) { f11 = pRow1[i - 1]; f12 = pRow1[i]; f13 = pRow1[i + 1]; f21 = pRow2[i - 1]; f22 = pRow2[i]; f23 = pRow2[i + 1]; row[i] = (f22 > f11) && (f22 > f12) && (f22 > f13) && (f22 > f21) && (f22 > mFilterThreshold) && (f22 > f23); } } // gather all peaks. int nPeaks = 0; for (int j=0; j<h; j++) { auto& mapRow = map[j]; for (int i=0; i < w; i++) { // if peak if (mapRow[i]) { float z = in[j*w + i]; peaks[nPeaks++] = Touch{.x = static_cast<float>(i), .y = static_cast<float>(j), .z = z}; if (nPeaks >= kMaxPeaks) break; } } } if(nPeaks > 1) { std::sort(peaks.begin(), peaks.begin() + nPeaks, [](Touch a, Touch b){ return a.z > b.z; } ); } // correct and clip int nTouches = std::min(nPeaks, (int)kMaxTouches); for(int i=0; i<nTouches; ++i) { Touch p = peaks[i]; if(p.z < mFilterThreshold) break; Touch px = correctPeakX(p, in); Touch pxy = correctPeakY(px, in); touches[i] = peakToTouch(pxy); } return touches; } // match incoming touches in x with previous frame of touches in x1. // for each possible touch slot, output the touch x closest in location to the previous frame. // if the incoming touch is a continuation of the previous one, set its age (w) to 1, otherwise to 0. // if there is no incoming touch to match with a previous one at index i, and no new touch needs index i, the position at index i will be maintained. // TODO first touch below filter threshold(?) is on one index, then active touch switches index?! investigate. TouchArray TouchTracker::matchTouches(const TouchArray& x, const TouchArray& x1) { const float kMaxConnectDist = 2.f; TouchArray newTouches{}; std::array<int, kMaxTouches> forwardMatchIdx; forwardMatchIdx.fill(-1); std::array<int, kMaxTouches> reverseMatchIdx; reverseMatchIdx.fill(-1); // for each previous touch, find minimum distance to a current touch. for(int i=0; i<mMaxTouchesPerFrame; ++i) { float minDist = MAXFLOAT; Touch prev = x1[i]; for(int j=0; j < mMaxTouchesPerFrame; ++j) { Touch curr = x[j]; if((curr.z > mFilterThreshold) && (prev.z > mFilterThreshold)) { float distToCurrentTouch = cityBlockDistanceXYZ(prev, curr, 20.f); if(distToCurrentTouch < minDist) { forwardMatchIdx[i] = j; minDist = distToCurrentTouch; } } } } // for each current touch, find minimum distance to a previous touch for(int i=0; i<mMaxTouchesPerFrame; ++i) { float minDist = MAXFLOAT; Touch curr = x[i]; for(int j=0; j < mMaxTouchesPerFrame; ++j) { Touch prev = x1[j]; if((curr.z > mFilterThreshold) && (prev.z > mFilterThreshold)) { float distToPreviousTouch = cityBlockDistanceXYZ(prev, curr, 20.f); if(distToPreviousTouch < minDist) { reverseMatchIdx[i] = j; minDist = distToPreviousTouch; } } } } // get mutual matches std::array<int, kMaxTouches> mutualMatches; mutualMatches.fill(0); for(int i=0; i<mMaxTouchesPerFrame; ++i) { int prevIdx = reverseMatchIdx[i]; if(prevIdx >= 0) { if(forwardMatchIdx[prevIdx] == i) { mutualMatches[i] = true; } } } std::array<bool, kMaxTouches> currWrittenToNew; currWrittenToNew.fill(false); // first, continue mutually matched touches for(int i=0; i<mMaxTouchesPerFrame; ++i) { if(mutualMatches[i]) { int j = reverseMatchIdx[i]; Touch curr = x[i]; Touch prev = x1[j]; { // touch is continued, mark as connected and write to new touches curr.age = (cityBlockDistanceXYZ(prev, curr, 0.f) < kMaxConnectDist); newTouches[j] = curr; currWrittenToNew[i] = true; } } } // now take care of any remaining nonzero current touches for(int i=0; i<mMaxTouchesPerFrame; ++i) { Touch curr = x[i]; if((!currWrittenToNew[i]) && (curr.z > mFilterThreshold)) { int freeIdx = -1; float minDist = MAXFLOAT; // first, try to match same touch index (important for decay!) Touch prev = x1[i]; if(prev.z <= mFilterThreshold) { freeIdx = i; } // then try closest free touch if(freeIdx < 0) { for(int j=0; j<mMaxTouchesPerFrame; ++j) { Touch prev = x1[j]; if(prev.z <= mFilterThreshold) { float d = cityBlockDistanceXYZ(curr, prev, 0.f); if(d < minDist) { minDist = d; freeIdx = j; } } } } // if a free index was found, write the current touch if(freeIdx >= 0) { Touch free = x1[freeIdx]; curr.age = (cityBlockDistanceXYZ(free, curr, 0.f) < kMaxConnectDist); newTouches[freeIdx] = curr; } } } // fill in any free touches with previous touches at those indices. This will allow old touches to re-link if not reused. for(int i=0; i < mMaxTouchesPerFrame; ++i) { Touch t = newTouches[i]; if(t.z <= mFilterThreshold) { newTouches[i].x = (x1[i].x); newTouches[i].y = (x1[i].y); } } return newTouches; } // input: vec4<x, y, z, k> where k is 1 if the touch is connected to the previous touch at the same index. // TouchArray TouchTracker::filterTouchesXYAdaptive(const TouchArray& in, const TouchArray& inz1) { // these filter settings have a big and sort of delicate impact on play feel, so they are not user settable const float kFixedXYFreqMax = 20.f; const float kFixedXYFreqMin = 1.f; TouchArray out{}; for(int i=0; i<mMaxTouchesPerFrame; ++i) { float x = in[i].x; float y = in[i].y; float z = in[i].z; int age = in[i].age; float x1 = inz1[i].x; float y1 = inz1[i].y; // filter, or not, based on w from matchTouches float newX, newY; if(age > 0) { // get xy coeffs, adaptive based on z float freq = mapAndClipRange(0., 0.02, kFixedXYFreqMin, kFixedXYFreqMax, z); float omegaXY = freq*kTwoPi/mSampleRate; float kXY = expf(-omegaXY); float a0XY = 1.f - kXY; float b1XY = kXY; // onepole filters newX = (x*a0XY) + (x1*b1XY); newY = (y*a0XY) + (y1*b1XY); } else { newX = x; newY = y; } out[i] = Touch{.x = newX, .y = newY, .z = z, .age = age}; } return out; } TouchArray TouchTracker::filterTouchesZ(const TouchArray& in, const TouchArray& inz1, float upFreq, float downFreq) { const float omegaUp = upFreq*kTwoPi/mSampleRate; const float kUp = expf(-omegaUp); const float a0Up = 1.f - kUp; const float b1Up = kUp; const float omegaDown = downFreq*kTwoPi/mSampleRate; const float kDown = expf(-omegaDown); const float a0Down = 1.f - kDown; const float b1Down = kDown; TouchArray out{}; for(int i=0; i<mMaxTouchesPerFrame; ++i) { float x = in[i].x; float y = in[i].y; float z = in[i].z; float z1 = inz1[i].z; int age1 = inz1[i].age; float newZ; // filter z variable float dz = z - z1; if(dz > 0.f) { newZ = (z*a0Up) + (z1*b1Up); } else { newZ = (z*a0Down) + (z1*b1Down); } // gate with hysteresis bool gate1 = (age1 > 0); bool newGate = gate1; if(newZ > mOnThreshold) { newGate = true; } else if (newZ < mOffThreshold) { newGate = false; } // increment age int newAge = newGate ? (age1 + 1) : 0; // set state int newState = newGate ? (gate1 ? kTouchStateContinue : kTouchStateOn) : (gate1 ? kTouchStateOff : kTouchStateInactive); out[i] = Touch{.x=x, .y=y, .z=newZ, .dz=dz, .age=newAge, .state=newState}; } return out; } // if a touch has decayed below the filter threshold after z filtering, move it off the scene so it won't match to other nearby touches. TouchArray TouchTracker::exileUnusedTouches(const TouchArray& preFiltered, const TouchArray& postFiltered) { TouchArray out(preFiltered); for(int i = 0; i < mMaxTouchesPerFrame; ++i) { Touch a = preFiltered[i]; Touch b = postFiltered[i]; if(b.x > 0.f) { if(b.z <= mFilterThreshold) { a.x = (-1.f); a.y = (-10.f); a.z = (0.f); } } out[i] = a; } return out; } // rotate order of touches, changing order every time there is a new touch in a frame. // side effect: writes to mRotateShuffleOrder TouchArray TouchTracker::rotateTouches(const TouchArray& in) { TouchArray touches(in); if(mMaxTouchesPerFrame > 1) { bool doRotate = false; for(int i = 0; i < mMaxTouchesPerFrame; ++i) { if(in[i].age == 1) { // we have a new touch at index i. doRotate = true; break; } } if(doRotate) { // rotate the indices of all free or new touches in the shuffle order int nFree = 0; std::array<int, kMaxTouches> freeIndexes; for(int i=0; i<mMaxTouchesPerFrame; ++i) { if((in[i].z < mFilterThreshold) || (in[i].age == 1)) { freeIndexes[nFree++] = i; } } if(nFree > 1) { int first = mRotateShuffleOrder[freeIndexes[0]]; for(int i=0; i < nFree - 1; ++i) { mRotateShuffleOrder[freeIndexes[i]] = mRotateShuffleOrder[freeIndexes[i + 1]]; } mRotateShuffleOrder[freeIndexes[nFree - 1]] = first; } } // shuffle for(int i = 0; i < mMaxTouchesPerFrame; ++i) { touches[mRotateShuffleOrder[i]] = in[i]; } } return touches; }
typename enable_if<is_interval_set<Type>, bool>::type is_joinable(typename Type::iterator it_, typename Type::iterator next_, Type* = 0) { return touches(*it_, *next_); }
void SparseTileLayoutData<Dim>::calcGCFillList() { if(!this->initialized() || !this->hasInternalGuards_m) return; this->gcFillList_m.clear(); gcBorderFillList_m.clear(); typedef Node<Domain_t,AllocatedDomain_t> NNode_t; typedef std::vector<NNode_t> TouchList_t; TouchList_t tlist; // first we do the internal overlap regions typename List_t::iterator start = this->all_m.begin(); typename List_t::iterator end = this->all_m.end(); for ( ; start!=end; ++start) { touches((*start)->allocated(), std::back_inserter(tlist), TouchesConstructNodeObj()); // now pack the tlist into the GCFillInfo object // The if test is to remove the self-touch entry typename TouchList_t::iterator GCLstart = tlist.begin(); typename TouchList_t::iterator GCLend = tlist.end(); for( ; GCLstart != GCLend ;++GCLstart) { if(GCLstart->globalID() == (*start)->globalID()) { tlist.erase(GCLstart); break; } } GCLstart = tlist.begin(); GCLend = tlist.end(); for ( ; GCLstart!=GCLend ; ++GCLstart ) { // removed the external guard layer area. this->gcFillList_m.push_back(GCFillInfo_t((*GCLstart).domain(), (*GCLstart).globalID(), (*start)->globalID())); } tlist.clear(); } // Next, generate the list of all the internalGuardLayer // regions, and 'subtract' the above list from it to produce // a list of internal guard layers that will be filled externally. std::vector<GCBorderFillInfo> bfv; start = this->all_m.begin(); for ( ; start!=this->all_m.end(); ++start) { for(int d=0;d<Dim;++d) { Domain_t gcdom( (*start)->allocated()); int max = (*start)->allocated()[d].last(); int min = max - this->internalGuards_m.upper(d) + 1; gcdom[d] = Interval<1>(min, max); gcdom = intersect(this->innerdomain_m,gcdom); if (gcdom.size()>0) { bfv.push_back(GCBorderFillInfo(gcdom, (*start)->globalID() )); } // now do the other side of this dimension. gcdom = (*start)->allocated(); min = (*start)->allocated()[d].first(); max = min + this->internalGuards_m.lower(d) -1; gcdom[d] = Interval<1>(min, max); gcdom = intersect(this->innerdomain_m,gcdom); if (gcdom.size() > 0) { bfv.push_back(GCBorderFillInfo(gcdom,(*start)->globalID())); } } } // remove overlap of GCFillInfo on GCBorderFillInfo std::vector<Domain_t> temp2,temp3,temp4; std::vector<GCBorderFillInfo> temp; BorderFillIterator_t bst = bfv.begin(); BorderFillIterator_t ben = bfv.end(); for ( ; bst != ben ; ++bst) { FillIterator_t gst = this->beginFillList(); FillIterator_t gen = this->endFillList(); temp2.clear(); temp2.push_back(bst->domain()); for ( ; gst!=gen ; ++gst ) { typename std::vector<Domain_t>::iterator ts = temp2.begin(); for ( ; ts != temp2.end() ; ++ts ) { temp3 = DomainRemoveOverlap(*ts,gst->domain_m); temp4.insert(temp4.end(),temp3.begin(),temp3.end()); } temp2 = temp4; temp4.clear(); } typename std::vector<Domain_t>::iterator ts = temp2.begin(); for( ; ts != temp2.end(); ++ts) temp.push_back(GCBorderFillInfo(*ts, bst->patchID() )); } //gcBorderFillList_m.clear(); gcBorderFillList_m = temp; }
int NPC_can_walk( NPC* _pNPC, bomb* _pBomb, NPC** _NPCs, int _NPCCount, map* _pMap, int _dir ) { // NPC's collide with the map, with other NPCs(not yet) and with the bomb switch ( _dir ) { case UP: { // change NPC direction even if he can't walk _pNPC->direction = UP; // check if upwards square is a destructible or undestructible block which means NPC can't walk there int upwards_square_is_blocked = ( _pMap->map_data[_pNPC->i - 1][_pNPC->j].block_type == DESTRUCTIBLE_BLOCK || _pMap->map_data[_pNPC->i - 1][_pNPC->j].block_type == INDESTRUCTIBLE_BLOCK ) ? 1 : 0; int upwards_square_has_bomb = ( (_pNPC->i - 1) == _pBomb->i ) && ( _pNPC->j == _pBomb->j ) ? 1 : 0; // if upwards block is des/indes then check if NPC is colliding with or touching upwards block if he isn't, he can walk up if ( upwards_square_is_blocked ) { rect NPC = { _pNPC->left, _pNPC->top, _pNPC->right, _pNPC->bottom }; rect block = { _pMap->map_data[_pNPC->i - 1][_pNPC->j].left, _pMap->map_data[_pNPC->i - 1][_pNPC->j].top, _pMap->map_data[_pNPC->i - 1][_pNPC->j].right, _pMap->map_data[_pNPC->i - 1][_pNPC->j].bottom }; if ( collides( NPC, block ) || touches( NPC, block ) ) return 0; else return 1; } else if ( upwards_square_has_bomb && _pBomb->active ) { rect NPC = { _pNPC->left, _pNPC->top, _pNPC->right, _pNPC->bottom }; rect bomb = { _pBomb->left, _pBomb->top, _pBomb->right, _pBomb->bottom }; if ( collides( NPC, bomb ) || touches( NPC, bomb ) ) return 0; else return 1; } else { // left allign NPC if he already isn't _pNPC->left = _pMap->map_data[_pNPC->i][_pNPC->j].left; return 1; } break; } case RIGHT: { // change NPC direction even if he can't walk _pNPC->direction = RIGHT; // check if rightmost square is a destructible or undestructible block which means NPC can't walk there int rightmost_square_is_blocked = ( _pMap->map_data[_pNPC->i][_pNPC->j + 1].block_type == DESTRUCTIBLE_BLOCK || _pMap->map_data[_pNPC->i][_pNPC->j + 1].block_type == INDESTRUCTIBLE_BLOCK ) ? 1 : 0; int rightmost_square_has_bomb = ( _pNPC->i == _pBomb->i ) && ( (_pNPC->j + 1) == _pBomb->j ) ? 1 : 0; if ( rightmost_square_is_blocked ) { rect NPC = { _pNPC->left, _pNPC->top, _pNPC->right, _pNPC->bottom }; rect block = { _pMap->map_data[_pNPC->i][_pNPC->j + 1].left, _pMap->map_data[_pNPC->i][_pNPC->j + 1].top, _pMap->map_data[_pNPC->i][_pNPC->j + 1].right, _pMap->map_data[_pNPC->i][_pNPC->j + 1].bottom }; if ( collides( NPC, block ) || touches( NPC, block ) ) return 0; else return 1; } else if ( rightmost_square_has_bomb && _pBomb->active ) { rect NPC = { _pNPC->left, _pNPC->top, _pNPC->right, _pNPC->bottom }; rect bomb = { _pBomb->left, _pBomb->top, _pBomb->right, _pBomb->bottom }; if ( collides( NPC, bomb ) || touches( NPC, bomb ) ) return 0; else return 1; } else { // top allign NPC if he already isn't _pNPC->top = _pMap->map_data[_pNPC->i][_pNPC->j].top; return 1; } break; } case DOWN: { // change NPC direction even if he can't walk _pNPC->direction = DOWN; // check if downwards square is a destructible or undestructible block which means NPC can't walk there int downwards_square_is_blocked = ( _pMap->map_data[_pNPC->i + 1][_pNPC->j].block_type == DESTRUCTIBLE_BLOCK || _pMap->map_data[_pNPC->i + 1][_pNPC->j].block_type == INDESTRUCTIBLE_BLOCK ) ? 1 : 0; int downwards_square_has_bomb = ( (_pNPC->i + 1) == _pBomb->i ) && ( _pNPC->j == _pBomb->j ) ? 1 : 0; if ( downwards_square_is_blocked ) { rect NPC = { _pNPC->left, _pNPC->top, _pNPC->right, _pNPC->bottom }; rect block = { _pMap->map_data[_pNPC->i + 1][_pNPC->j].left, _pMap->map_data[_pNPC->i + 1][_pNPC->j].top, _pMap->map_data[_pNPC->i + 1][_pNPC->j].right, _pMap->map_data[_pNPC->i + 1][_pNPC->j].bottom }; if ( collides( NPC, block ) || touches( NPC, block ) ) return 0; else return 1; } else if ( downwards_square_has_bomb && _pBomb->active ) { rect NPC = { _pNPC->left, _pNPC->top, _pNPC->right, _pNPC->bottom }; rect bomb = { _pBomb->left, _pBomb->top, _pBomb->right, _pBomb->bottom }; if ( collides( NPC, bomb ) || touches( NPC, bomb ) ) return 0; else return 1; } else { // left allign NPC if he already isn't _pNPC->left = _pMap->map_data[_pNPC->i][_pNPC->j].left; return 1; } break; } case LEFT: { // change NPC direction even if he can't walk _pNPC->direction = LEFT; // check if leftmost square is a destructible or undestructible block which means NPC can't walk there int leftmost_square_is_blocked = ( _pMap->map_data[_pNPC->i][_pNPC->j - 1].block_type == DESTRUCTIBLE_BLOCK || _pMap->map_data[_pNPC->i][_pNPC->j - 1].block_type == INDESTRUCTIBLE_BLOCK ) ? 1 : 0; int leftmost_square_has_bomb = ( _pNPC->i == _pBomb->i ) && ( (_pNPC->j - 1) == _pBomb->j ) ? 1 : 0; if ( leftmost_square_is_blocked ) { rect NPC = { _pNPC->left, _pNPC->top, _pNPC->right, _pNPC->bottom }; rect block = { _pMap->map_data[_pNPC->i][_pNPC->j - 1].left, _pMap->map_data[_pNPC->i][_pNPC->j - 1].top, _pMap->map_data[_pNPC->i][_pNPC->j - 1].right, _pMap->map_data[_pNPC->i][_pNPC->j - 1].bottom }; if ( collides( NPC, block ) || touches( NPC, block ) ) return 0; else return 1; } else if ( leftmost_square_has_bomb && _pBomb->active ) { rect NPC = { _pNPC->left, _pNPC->top, _pNPC->right, _pNPC->bottom }; rect bomb = { _pBomb->left, _pBomb->top, _pBomb->right, _pBomb->bottom }; if ( collides( NPC, bomb ) || touches( NPC, bomb ) ) return 0; else return 1; } else { // top allign NPC if he already isn't _pNPC->top = _pMap->map_data[_pNPC->i][_pNPC->j].top; return 1; } break; } } }
int UniformGridLayoutData<Dim>::touchesAllocLocal(const OtherDomain &d, OutIter o, const ConstructTag &ctag) const { // If there are no internal guard cells, then this calculation is the // same as the normal touches calculation. if (!this->hasInternalGuards_m) return touches(d,o,ctag); int i, count = 0; // Make sure we have a valid touching domain. PAssert(this->initialized()); PAssert(contains(this->domain_m, d)); // Find the starting and ending grid positions, and store as an // Interval. Interval<Dim> box = Pooma::NoInit(); for (i = 0; i < Dim; ++i) { int a, b; // This part is unchanged from touches. What we're going to do // here is simply extend the range in each direction by one block // and then let the intersection calculation below sort out if // there is actually an intersection. Otherwise we'd have to do // comparisons on all blocks up here and then still do the // intersection on the remaining blocks below. On average, this // should be slightly faster I think. if (!this->hasExternalGuards_m) { a = (d[i].min() - this->firsti_m[i]) / blocksizes_m[i]; b = (d[i].max() - this->firsti_m[i]) / blocksizes_m[i]; } else { // If we're in the lower guards, this will fall // through to give zero. a = b = 0; int pos = d[i].min(); int last = this->innerdomain_m[i].last(); int del = pos - this->firsti_m[i]; if (del >= 0) if (pos <= last) a = del / blocksizes_m[i]; else a = allDomain_m[i].last(); pos = d[i].max(); del = pos - this->firsti_m[i]; if (del >= 0) if (pos <= last) b = del / blocksizes_m[i]; else b = allDomain_m[i].last(); } // Now we check that we're not at the ends of the domain for the // brick of blocks, and extend the region accordingly. if (a > 0) --a; if (b < allDomain_m[i].last()) ++b; box[i] = Interval<1>(a, b); } // Figure the type of the domain resulting from the intersection. typedef typename IntersectReturnType<Domain_t,OtherDomain>::Type_t OutDomain_t; OutDomain_t outDomain = Pooma::NoInit(); // Generate the type of the node pushed on the output iterator. typedef Node<OutDomain_t,Domain_t> OutNode_t; // Iterate through the Interval grid positions. typename Interval<Dim>::const_iterator boxiter = box.begin(); while (boxiter != box.end()) { // Calculate the linear position of the current node. int indx = (*boxiter)[0].first(); for (i = 1; i < Dim; ++i) indx += blockstride_m[i] * (*boxiter)[i].first(); // Get that node, intersect the *allocated* domain with the // requested one, and write the result out to the output iterator. PAssert(indx >= 0 && indx < this->local_m.size()); outDomain = intersect(d, this->local_m[indx]->allocated()); // We can no longer assert that outDomain is not empty since // we extended the search box without checking. Thus we now // have an if tests around the output. if (!outDomain.empty()) { *o = touchesConstruct(outDomain, this->local_m[indx]->allocated(), this->local_m[indx]->affinity(), this->local_m[indx]->context(), this->local_m[indx]->globalID(), this->local_m[indx]->localID(), ctag); } // Increment output iterator, count, and grid iterator. ++o; ++count; ++boxiter; } // Return the number of non-empty domains we found. return count; }
int player_can_walk( player* _pPlayer, map* _pMap, int _dir ) { switch ( _dir ) { case UP: { // change player direction even if he can't walk _pPlayer->direction = UP; // check if upwards square is a destructible or undestructible block which means player can't walk there int upwards_square_is_blocked = ( _pMap->map_data[_pPlayer->i - 1][_pPlayer->j].block_type == DESTRUCTIBLE_BLOCK || _pMap->map_data[_pPlayer->i - 1][_pPlayer->j].block_type == INDESTRUCTIBLE_BLOCK ) ? 1 : 0; // if upwards block is des/indes then check if player is colliding with or touching upwards block if he isn't, he can walk up if ( upwards_square_is_blocked ) { rect player = { _pPlayer->left, _pPlayer->top, _pPlayer->right, _pPlayer->bottom }; rect block = { _pMap->map_data[_pPlayer->i - 1][_pPlayer->j].left, _pMap->map_data[_pPlayer->i - 1][_pPlayer->j].top, _pMap->map_data[_pPlayer->i - 1][_pPlayer->j].right, _pMap->map_data[_pPlayer->i - 1][_pPlayer->j].bottom }; if ( collides( player, block ) || touches( player, block ) ) return 0; else return 1; } else { // left allign player if he already isn't _pPlayer->left = _pMap->map_data[_pPlayer->i][_pPlayer->j].left; return 1; } break; } case RIGHT: { // change player direction even if he can't walk _pPlayer->direction = RIGHT; // check if rightmost square is a destructible or undestructible block which means player can't walk there int rightmost_square_is_blocked = ( _pMap->map_data[_pPlayer->i][_pPlayer->j + 1].block_type == DESTRUCTIBLE_BLOCK || _pMap->map_data[_pPlayer->i][_pPlayer->j + 1].block_type == INDESTRUCTIBLE_BLOCK ) ? 1 : 0; if ( rightmost_square_is_blocked ) { rect player = { _pPlayer->left, _pPlayer->top, _pPlayer->right, _pPlayer->bottom }; rect block = { _pMap->map_data[_pPlayer->i][_pPlayer->j + 1].left, _pMap->map_data[_pPlayer->i][_pPlayer->j + 1].top, _pMap->map_data[_pPlayer->i][_pPlayer->j + 1].right, _pMap->map_data[_pPlayer->i][_pPlayer->j + 1].bottom }; if ( collides( player, block ) || touches( player, block ) ) return 0; else return 1; } else { // top allign player if he already isn't _pPlayer->top = _pMap->map_data[_pPlayer->i][_pPlayer->j].top; return 1; } break; } case DOWN: { // change player direction even if he can't walk _pPlayer->direction = DOWN; // check if downwards square is a destructible or undestructible block which means player can't walk there int downwards_square_is_blocked = ( _pMap->map_data[_pPlayer->i + 1][_pPlayer->j].block_type == DESTRUCTIBLE_BLOCK || _pMap->map_data[_pPlayer->i + 1][_pPlayer->j].block_type == INDESTRUCTIBLE_BLOCK ) ? 1 : 0; if ( downwards_square_is_blocked ) { rect player = { _pPlayer->left, _pPlayer->top, _pPlayer->right, _pPlayer->bottom }; rect block = { _pMap->map_data[_pPlayer->i + 1][_pPlayer->j].left, _pMap->map_data[_pPlayer->i + 1][_pPlayer->j].top, _pMap->map_data[_pPlayer->i + 1][_pPlayer->j].right, _pMap->map_data[_pPlayer->i + 1][_pPlayer->j].bottom }; if ( collides( player, block ) || touches( player, block ) ) return 0; else return 1; } else { // left allign player if he already isn't _pPlayer->left = _pMap->map_data[_pPlayer->i][_pPlayer->j].left; return 1; } break; } case LEFT: { // change player direction even if he can't walk _pPlayer->direction = LEFT; // check if leftmost square is a destructible or undestructible block which means player can't walk there int leftmost_square_is_blocked = ( _pMap->map_data[_pPlayer->i][_pPlayer->j - 1].block_type == DESTRUCTIBLE_BLOCK || _pMap->map_data[_pPlayer->i][_pPlayer->j - 1].block_type == INDESTRUCTIBLE_BLOCK ) ? 1 : 0; if ( leftmost_square_is_blocked ) { rect player = { _pPlayer->left, _pPlayer->top, _pPlayer->right, _pPlayer->bottom }; rect block = { _pMap->map_data[_pPlayer->i][_pPlayer->j - 1].left, _pMap->map_data[_pPlayer->i][_pPlayer->j - 1].top, _pMap->map_data[_pPlayer->i][_pPlayer->j - 1].right, _pMap->map_data[_pPlayer->i][_pPlayer->j - 1].bottom }; if ( collides( player, block ) || touches( player, block ) ) return 0; else return 1; } else { // top allign player if he already isn't _pPlayer->top = _pMap->map_data[_pPlayer->i][_pPlayer->j].top; return 1; } break; } } }