Jump to content
  • Advertisement
Sign in to follow this  
cloud007

birds-eye view scrolling

This topic is 4870 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm having trouble with birds-eye view scrolling. I'm making an RPG game with Visual C++ and MFC, only problem is, I can't seem to make the character scroll correctly. To see the source code for what I have so far, see: http://www.albany.edu/~tv387711/spritemapwalk.zip Any help for me? I'm new at this. Note: the tw*.gif files are not included. They are, for reference, 30 x 48 sprite images. [Edited by - cloud007 on June 18, 2005 2:54:06 PM]

Share this post


Link to post
Share on other sites
Advertisement
Try posting the related code section here instead, describing what you want it to do and what actually happens. You generally get more replies if viewers don't have to download anything in order to help you.

Share this post


Link to post
Share on other sites
Okay, here's the code for the main view:

brstructs.h:

#pragma once
#include <windows.h>

/* Structure of map file:
*
* MapHeader
* (contents of a bitmap file)
* BoundRectDataHeader -|
* = BoundRectDataFile
* RECTs -|
*/


struct MapHeader {
DWORD fileSize; // total file size
DWORD bmpSize; // size of bitmap portion
DWORD brdSize; // size of bound-rect data portion
};

struct BoundRectDataHeader {
DWORD width; // width of map
DWORD height; // height of map
DWORD nRects; // number of RECTs following
};

struct BoundRectDataFile {
BoundRectDataHeader brdh;
RECT brdd[1]; // no-mans land zones
};




mainview.h:

// mainview.h : interface of the MainView class
//


#pragma once

#include "brstructs.h"

// MainView window

class MainView : public CWnd
{
// Construction
public:
MainView();

// Attributes
public:

// Operations
public:

// Overrides
protected:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

// Implementation
public:
virtual ~MainView();

// Generated message map functions
protected:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnPaint();
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg void OnClose();
DECLARE_MESSAGE_MAP()
private:
Gdiplus::Image *back[3]; // backward-facing sprites
Gdiplus::Image *front[3]; // forward-facing sprites
Gdiplus::Image *right[3]; // right-facing sprites
Gdiplus::Image *left[3]; // left-facing sprites
BoundRectDataFile *pbrdf; // map data
LPVOID bgbits; // background DI bits
HBITMAP bg; // background bitmap handle
CDC bgdc; // background bitmap DC
void readBitmapFile(CFile &file); // reads bitmap portion of map file
void readMap(const char *fileName); // reads map file and initializes
member fields
CWinThread *kbThread; // keyboard input thread
};

UINT threadFunc(LPVOID vParam);




mainview.cpp:

// mainview.cpp : implementation of the MainView class
//

#include "stdafx.h"
#include "spritemapwalk.h"
#include "mainview.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

using namespace Gdiplus;

// MainView
bool threadRunning, threadWaiting;
/* abs(facingDir) == 1 : horizontal
* abs(facingDir) == 2 : vertical
*/

int currentHDir, currentVDir, facingDir;
int current; // current image index
CRect scroll; // area where movement causes scrolling
CRect currentPos;
CPoint ulBgCorner(0, 0); // upper-left background corner of visible area
const static int seq[] = {0, 1, 0, 2}; // sprite sequence
BITMAPINFO *pbgbi; // background bitmap info

// calculates the center point of rect
CPoint rectCenter(const CRect &rect);

MainView::MainView()
{
threadRunning = threadWaiting = true;
currentHDir = currentVDir = 0;
facingDir = 1;
current = 0;
currentPos.SetRectEmpty();
back[0] = Image::FromFile(L"twback0.gif");
back[1] = Image::FromFile(L"twback1.gif");
back[2] = Image::FromFile(L"twback2.gif");
front[0] = Image::FromFile(L"twfront0.gif");
front[1] = Image::FromFile(L"twfront1.gif");
front[2] = Image::FromFile(L"twfront2.gif");
left[0] = Image::FromFile(L"twleft0.gif");
left[1] = Image::FromFile(L"twleft1.gif");
left[2] = Image::FromFile(L"twleft2.gif");
right[0] = Image::FromFile(L"twright0.gif");
right[1] = Image::FromFile(L"twright1.gif");
right[2] = Image::FromFile(L"twright2.gif");
// set image to 67% zoom
currentPos.right = (back[0]->GetWidth() * 2) / 3;
currentPos.bottom = (back[0]->GetHeight() * 2) / 3;
}

MainView::~MainView()
{
for(int i = 0; i < 3; ++i) {
delete back;
delete front;
delete left;
delete right;
}
bgdc.DeleteDC();
::DeleteObject(bg);
::LocalFree((HLOCAL)pbgbi);
::LocalFree((HLOCAL)bgbits);
::LocalFree((HLOCAL)pbrdf);
if(AfxIsValidAddress(kbThread, sizeof(CWinThread), FALSE))
delete kbThread;
}


BEGIN_MESSAGE_MAP(MainView, CWnd)
ON_WM_CREATE()
ON_WM_PAINT()
ON_WM_KEYDOWN()
ON_WM_KEYUP()
ON_WM_CLOSE()
END_MESSAGE_MAP()



// MainView message handlers

BOOL MainView::PreCreateWindow(CREATESTRUCT& cs)
{
if (!CWnd::PreCreateWindow(cs))
return FALSE;

cs.style &= ~WS_BORDER;
cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,
::LoadCursor(NULL, IDC_ARROW), reinterpret_cast<HBRUSH>
(COLOR_WINDOW+1), NULL);

return TRUE;
}

int MainView::OnCreate(LPCREATESTRUCT lpCreateStruct) {
int ret = CWnd::OnCreate(lpCreateStruct);
// initialize map variables
readMap("map1.map");
// begin input thread
kbThread = AfxBeginThread(threadFunc, (LPVOID)this);
return ret;
}

void MainView::OnPaint()
{
CPaintDC thisDc(this); // device context for painting
CDC dc;
dc.CreateCompatibleDC(&thisDc);
CPoint centerPoint, brCenterPoint;
CRect rt;
GetClientRect(&rt);
// calculate the bounds of the scroll rect
centerPoint.x = rt.Width() / 2;
centerPoint.y = rt.Height() / 2;
brCenterPoint.x = pbgbi->bmiHeader.biWidth - centerPoint.x;
brCenterPoint.y = pbgbi->bmiHeader.biHeight - centerPoint.y;
scroll = CRect(centerPoint, brCenterPoint);
// double-buffer
CBitmap bmp;
bmp.CreateCompatibleBitmap(&thisDc, rt.Width(), rt.Height());
dc.SelectObject(&bmp);
// copy background
dc.BitBlt(0, 0, rt.Width(), rt.Height(), &bgdc, 0, 0, SRCCOPY);
Image **set;
if(facingDir == -1) // left-face
set = left;
else if(facingDir == 1) // right-face
set = right;
else if(facingDir == -2) // back-face
set = back;
else // front-face
set = front;
Graphics g(dc);
g.DrawImage(set[seq[current]], currentPos.left, currentPos.top,
currentPos.Width(), currentPos.Height());
thisDc.BitBlt(0, 0, rt.Width(), rt.Height(), &dc, 0, 0, SRCCOPY);
dc.DeleteDC();
bmp.DeleteObject();
// Do not call CWnd::OnPaint() for painting messages
}

void MainView::readBitmapFile(CFile &file) {
BITMAPFILEHEADER bfh;
file.Read(&bfh, sizeof(BITMAPFILEHEADER));
DWORD bmiSize = bfh.bfOffBits - sizeof(BITMAPFILEHEADER);
pbgbi = (BITMAPINFO *)::LocalAlloc(LMEM_FIXED, bmiSize);
file.Read(&(pbgbi->bmiHeader), sizeof(BITMAPINFOHEADER));
DWORD tableSize = bfh.bfOffBits - (sizeof(BITMAPFILEHEADER) + sizeof
(BITMAPINFOHEADER));
file.Read(pbgbi->bmiColors, tableSize);
DWORD bitsSize = bfh.bfSize - bfh.bfOffBits;
bgbits = (LPVOID)::LocalAlloc(LMEM_FIXED, bitsSize);
file.Read(bgbits, bitsSize);
CWindowDC wndDc(this);
LPVOID dummy;
bg = ::CreateDIBSection(wndDc, pbgbi, DIB_RGB_COLORS, &dummy, NULL, 0);
::SetDIBits(wndDc, bg, 0, pbgbi->bmiHeader.biHeight, bgbits, pbgbi,
DIB_RGB_COLORS);
bgdc.CreateCompatibleDC(&wndDc);
bgdc.SelectObject(bg);
}

void MainView::readMap(const char *fileName) {
CFile file(fileName, CFile::modeRead);
MapHeader maphdr;
file.Read(&maphdr, sizeof(MapHeader));
readBitmapFile(file);
pbrdf = (BoundRectDataFile *)::LocalAlloc(LMEM_FIXED, maphdr.brdSize);
file.Read(pbrdf, maphdr.brdSize);
file.Close();
}

CPoint rectCenter(const CRect &rect) {
return CPoint(rect.left + rect.Width() / 2, rect.top + rect.Height() /
2);
}

UINT threadFunc(LPVOID vParam) {
MainView *pmv = (MainView *)vParam;
while(threadRunning) {
if(!threadWaiting) {
CRect rt;
pmv->GetClientRect(&rt);
CPoint pt;
if((currentHDir < 0) && (currentPos.left > 0)) {
currentPos.OffsetRect(-5, 0);
pt = rectCenter(currentPos);
if(scroll.PtInRect(pt)) {
ulBgCorner.x -= 5;
pmv->ScrollWindowEx(-5, 0, NULL,
NULL, NULL, NULL, SW_INVALIDATE);
}
}
else if((currentHDir > 0) && (currentPos.right <
pbgbi->bmiHeader.biWidth)) {
currentPos.OffsetRect(5, 0);
pt = rectCenter(currentPos);
if(scroll.PtInRect(pt)) {
ulBgCorner.x += 5;
pmv->ScrollWindowEx(5, 0, NULL,
NULL, NULL, NULL, SW_INVALIDATE);
}
}
if((currentVDir < 0) && (currentPos.top > 0)) {
currentPos.OffsetRect(0, -5);
pt = rectCenter(currentPos);
if(scroll.PtInRect(pt)) {
ulBgCorner.y -= 5;
pmv->ScrollWindowEx(0, -5, NULL,
NULL, NULL, NULL, SW_INVALIDATE);
}
}
else if((currentVDir > 0) && (currentPos.bottom
< pbgbi->bmiHeader.biHeight)) {
currentPos.OffsetRect(0, 5);
pt = rectCenter(currentPos);
if(scroll.PtInRect(pt)) {
ulBgCorner.y += 10;
pmv->ScrollWindowEx(0, 5, NULL,
NULL, NULL, NULL, SW_INVALIDATE);
}
}
facingDir = 0;
if((currentHDir != 0) || (currentVDir != 0)) {
if(currentHDir > 0)
facingDir = 1;
else if(currentHDir < 0)
facingDir = -1;
if(currentVDir > 0)
facingDir = 2;
else if(currentVDir < 0)
facingDir = -2;
current = (current + 1) % (sizeof(seq) / sizeof
(int));
}
else
current = 0;
pmv->InvalidateRect(NULL, FALSE);
pmv->UpdateWindow();
::Sleep(125);
}
}
AfxEndThread(0, TRUE);
return 0;
}

void MainView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) {
switch(nChar) {
case VK_UP:
currentVDir = -1;
threadWaiting = false;
break;
case VK_DOWN:
currentVDir = 1;
threadWaiting = false;
break;
case VK_LEFT:
currentHDir = -1;
threadWaiting = false;
break;
case VK_RIGHT:
currentHDir = 1;
threadWaiting = false;
break;
default:
CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}
}

void MainView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) {
switch(nChar) {
case VK_UP:
case VK_DOWN:
currentVDir = 0;
threadWaiting = true;
current = 0;
InvalidateRect(NULL, FALSE);
UpdateWindow();
break;
case VK_LEFT:
case VK_RIGHT:
currentHDir = 0;
threadWaiting = true;
current = 0;
InvalidateRect(NULL, FALSE);
UpdateWindow();
break;
default:
CWnd::OnKeyUp(nChar, nRepCnt, nFlags);
}
}

void MainView::OnClose() {
threadRunning = false;
CWnd::OnClose();
}




What this does:
This code, when included with the other files (irrelevant to scrolling), shows
a window where a sprite image is put onto a map background. I have not
included code for keeping the sprite out of so-called "no-mans lands", because
I have not completed the scroll functions yet. The sprite is supposed to stay
in the center of the window when scrolling, and the background should move
smoothly with the character, but this is not what happens. Either the sprite
moves too fast and/or the background does not move correctly.

[Edited by - cloud007 on June 20, 2005 10:35:48 AM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by cloud007
...

Sorry for the long message, but I don't know how to include text areas for
code in messages. Could someone tell me how? Thanks.


Use [ source] and [ /source] without the spaces.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!