2012-11-30 28 views
7

मेरे पास यह 800x600square है जो मैं स्क्रीन पर आकर्षित करना चाहता हूं। मैं इसमें सर्कल 'कट' करना चाहता हूं (जहां अल्फा 0 होगा)। असल में मैं इस पूरे आयत को मानचित्र पर खींच रहा हूं, इसलिए मैंने इन 'मंडलियों' को खींचा है, आप नक्शा देख सकते हैं, अन्यथा आप ग्रे स्क्वायरएसडीएल - ड्राइंग 'नकारात्मक' मंडल (युद्ध का धुंध)

+0

तो क्या आप सर्कल छवि को सीधे मानचित्र के अल्फा चैनल में मुद्रित करना चाहते हैं? – Tommy

+0

मैं एक ग्रे बॉक्स रखना चाहता हूं, जिसमें सर्कल 'मिटाया गया' है, इसलिए मैं पूरी तरह से परत के माध्यम से ग्रे बॉक्स को खींचा जा रहा हूं। – will

उत्तर

24

तो, मुझे लगता है कि आप युद्ध के धुंध को जोड़ने की कोशिश कर रहे हैं आप में से एक खेल?

मेरे पास एक छोटे से डेमो था जिसे मैंने कुछ हफ्ते पहले एक * पथदर्शी दिखाने के लिए बनाया था, इसलिए मैंने सोचा कि मैं आपके लिए युद्ध के धुंध को जोड़ सकता हूं। यहाँ परिणाम है:

प्रारंभिक नक्शा

सबसे पहले, आप

फिर एक पूरा नक्शा, पूरी तरह से दिखाई

Full Map

कोहरा के साथ शुरू, मैं करने के लिए एक सतह जोड़ा पूरी स्क्रीन को कवर करें (ध्यान दें कि मेरा नक्शा स्क्रीन से छोटा है, इसलिए इस मामले के लिए मैंने बस स्कैन पर युद्ध का धुंध जोड़ा रीन, लेकिन अगर आप स्क्रॉल है, सुनिश्चित करें कि यह प्रत्येक नक्शे पिक्सेल 1 शामिल हैं: 1)

mFogOfWar = SDL_CreateRGBSurface(SDL_HWSURFACE, in_Width, in_Height, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); 
SDL_Rect screenRect = {0, 0, in_Width, in_Height}; 
SDL_FillRect(mFogOfWar, &screenRect, 0xFF202020); 

उसके बाद, आप यह आकर्षित करने की आवश्यकता है ... मैं खेल वस्तुओं ड्राइंग के बाद और यूआई निकालने से पहले इस कॉल जोड़ा

DrawSurface(mFogOfWar, 0, 0); 

कहाँ

void RenderingManager::DrawSurface(SDL_Surface* in_Surface, int in_X, int in_Y) 
{ 
    SDL_Rect Dest = { in_X, in_Y, 0, 0 }; 
    SDL_BlitSurface(in_Surface, NULL, mScreen, &Dest); 
} 

कौन आपको निम्न परिणाम देना चाहिए:

Everything Fogged

"पंच भूतल"

मैं तो एक 32 बिट .png कि इस तरह दिखता है बनाया (बिसात से पता चलता अल्फा)

Punch

जब मेरे मुख्य चरित्र प्रतिपादन, मैं इस कॉल जोड़ा :

gRenderingManager.RemoveFogOfWar(int(mX) + SPRITE_X_OFFSET, int(mY) + SPRITE_Y_OFFSET); 

ऑफ़सेट केवल स्प्राइट के साथ पंच को केंद्र में रखने के लिए है, मूल रूप से, जो मैं RemoveFogOfWar पर जा रहा हूं वह मेरे स्प्राइट का केंद्र है।

युद्ध

अब युद्ध के कोहरे के मांस के कोहरे निकालें। मैंने दो संस्करण किए, एक जहां युद्ध का धुंध स्थायी रूप से हटा दिया जाता है और एक जहां युद्ध का धुंध रीसेट हो जाता है। युद्ध रीसेट का मेरा धुंध मेरी punch सतह पर निर्भर करता है जहां अल्फा 0 पर रीसेट हो जाता है और तथ्य यह है कि मेरे चरित्र प्रति फ्रेम में कॉन्टूर की तुलना में कम पिक्सेल की चाल चलती है, अन्यथा मैं Rect रखूंगा जहां मेरा पंच लागू किया गया था और मैं फिर से नया पंच खींचने से पहले इसे फिर से भर दूंगा।

चूंकि मुझे एसडीएल के साथ "गुणा" मिश्रण नहीं मिला, इसलिए मैंने एक साधारण कार्य लिखने का फैसला किया जो पंच सतह पर पुनरावृत्त करता है और युद्ध की सतह के धुंध पर अल्फा अपडेट करता है। सबसे महत्वपूर्ण हिस्सा वहाँ कुछ फसल कार्यों हो सकता है, लेकिन मैं जाँच परेशान नहीं किया करें कि आप अपने सतहों की सीमा के भीतर रहने बनाने के लिए है, इसलिए यह कोड के सबसे तक ले जाता है ...:

void RenderingManager::RemoveFogOfWar(int in_X, int in_Y) 
{ 
    const int halfWidth = mFogOfWarPunch->w/2; 
    const int halfHeight = mFogOfWarPunch->h/2; 

    SDL_Rect sourceRect = { 0, 0, mFogOfWarPunch->w, mFogOfWarPunch->h }; 
    SDL_Rect destRect = { in_X - halfWidth, in_Y - halfHeight, mFogOfWarPunch->w, mFogOfWarPunch->h }; 

    // Make sure our rects stays within bounds 
    if(destRect.x < 0) 
    { 
     sourceRect.x -= destRect.x; // remove the pixels outside of the surface 
     sourceRect.w -= sourceRect.x; // shrink to the surface, not to offset fog 
     destRect.x = 0; 
     destRect.w -= sourceRect.x; // shrink the width to stay within bounds 
    } 
    if(destRect.y < 0) 
    { 
     sourceRect.y -= destRect.y; // remove the pixels outside 
     sourceRect.h -= sourceRect.y; // shrink to the surface, not to offset fog 
     destRect.y = 0; 
     destRect.h -= sourceRect.y; // shrink the height to stay within bounds 
    } 

    int xDistanceFromEdge = (destRect.x + destRect.w) - mFogOfWar->w; 
    if(xDistanceFromEdge > 0) // we're busting 
    { 
     sourceRect.w -= xDistanceFromEdge; 
     destRect.w -= xDistanceFromEdge; 
    } 
    int yDistanceFromEdge = (destRect.y + destRect.h) - mFogOfWar->h; 
    if(yDistanceFromEdge > 0) // we're busting 
    { 
     sourceRect.h -= yDistanceFromEdge; 
     destRect.h -= yDistanceFromEdge; 
    } 

    SDL_LockSurface(mFogOfWar); 

    Uint32* destPixels = (Uint32*)mFogOfWar->pixels; 
    Uint32* srcPixels = (Uint32*)mFogOfWarPunch->pixels; 

    static bool keepFogRemoved = false; 

    for(int x = 0; x < destRect.w; ++x) 
    { 
     for(int y = 0; y < destRect.h; ++y) 
     { 
      Uint32* destPixel = destPixels + (y + destRect.y) * mFogOfWar->w + destRect.x + x; 
      Uint32* srcPixel = srcPixels + (y + sourceRect.y) * mFogOfWarPunch->w + sourceRect.x + x; 

      unsigned char* destAlpha = (unsigned char*)destPixel + 3; // fetch alpha channel 
      unsigned char* srcAlpha = (unsigned char*)srcPixel + 3; // fetch alpha channel 
      if(keepFogRemoved == true && *srcAlpha > 0) 
      { 
       continue; // skip this pixel 
      } 

      *destAlpha = *srcAlpha; 
     } 
    } 

    SDL_UnlockSurface(mFogOfWar); 
} 

कौन सा तो मुझे keepFogRemoved = false के साथ इस दे दी है के बाद भी चरित्र keepFogRemoved = true

fog of war permanent

के साथ चारों ओर

fog of war

और यह चला गया था

मान्यता

महत्वपूर्ण हिस्सा सुनिश्चित करें कि आप अपने पिक्सेल बफर के बाहर कुछ भी न लिखें, ताकि नकारात्मक ऑफसेट या ऑफसेट है कि आप चौड़ाई या ऊंचाई से बाहर लाना होगा के साथ बाहर देखने के लिए वास्तव में है। मेरे कोड को मान्य करने के लिए, मैं RemoveFogOfWar के लिए एक सरल कॉल जोड़ा जब माउस क्लिक किया और मैं एक "द्वारा बंद एक" समस्या

case SDL_MOUSEBUTTONDOWN: 
    { 
     if(Event.button.button == SDL_BUTTON_LEFT) 
     { 
      gRenderingManager.RemoveFogOfWar(Event.button.x, Event.button.y); 
     } 
     break; 
    } 

नोट्स नहीं था सुनिश्चित करने के लिए करने की कोशिश की कोनों और किनारों है

जाहिर है, आपको "पंच" के लिए 32 बिट्स बनावट की आवश्यकता नहीं है, लेकिन यह स्पष्ट तरीका था कि मैं आपको यह दिखाने के लिए सोच सकता था कि इसे कैसे किया जाए। यह 1 बिट प्रति पिक्सेल (चालू/बंद) के रूप में कम से कम किया जा सकता है। तुम भी कुछ ढाल जोड़ सकते हैं, और

if(*srcAlpha > *destAlpha) 
{ 
    continue; 
} 

की तरह कुछ करने के लिए

if(keepFogRemoved == true && *srcAlpha > 0) 
{ 
    continue; // skip this pixel 
} 

बदल इस तरह एक चिकनी मिश्रण रखने के लिए:

enter image description here

3 राज्य युद्ध के कोहरा

I सोचा कि मुझे यह जोड़ना चाहिए ... मैंने युद्ध के 3 राज्य कोहरे बनाने के लिए एक तरीका जोड़ा: visible, seen और fogged

ऐसा करने के लिए, मैं बस SDL_Rect रखता हूं जहां से मैंने युद्ध के कोहरे को "पेंच" किया है, और यदि अल्फा एक निश्चित मूल्य से कम है, तो मैं इसे उस मान पर क्लैंप करता हूं।

:

तो, बस सही पाश जहां युद्ध के कोहरे "मुक्का मारा" से पहले

for(int x = 0; x < mLastFogOfWarPunchPosition.w; ++x) 
{ 
    for(int y = 0; y < mLastFogOfWarPunchPosition.h; ++y) 
    { 
     Uint32* destPixel = destPixels + (y + mLastFogOfWarPunchPosition.y) * mFogOfWar->w + mLastFogOfWarPunchPosition.x + x; 
     unsigned char* destAlpha = (unsigned char*)destPixel + 3; 

     if(*destAlpha < 0x60) 
     { 
      *destAlpha = 0x60; 
     } 
    } 
} 
mLastFogOfWarPunchPosition = destRect; 

जोड़कर, मैं तुम्हें StarCraft की तरह खेल में हो सकता था क्या करने के लिए इसी तरह के युद्ध के कोहरे मिल

3 state

अब, के बाद से "देखा" युद्ध के कोहरे अर्द्ध पारदर्शी है, ताकि आप उन्हें है, लेकिन आप नहीं देखते हैं आप अपने प्रतिपादन विधि बदलाव करने को ठीक से "दुश्मन" है कि कोहरे में होगा क्लिप करने की आवश्यकता होगी अभी भी इलाके देखें।

आशा है कि इससे मदद मिलती है!

+6

मैं वास्तव में आपके द्वारा किए गए काम की सराहना करता हूं। यह एक ट्यूटोरियल की तरह है! +1 –

+0

@ BartekBanachewicz धन्यवाद! उम्मीद है कि जवाब पर्याप्त स्पष्ट है! :) – emartel

+0

woah। आदमी तुम अद्भुत हो! मैं स्टैक ओवरफ्लो के साथ अनुभव नहीं कर रहा हूं, क्या आपके और उत्तर देने के जवाब देने के अलावा मैं कुछ और कर सकता हूं? : पी – will