Advertisement

Tracking object locations

Started by June 01, 2002 08:10 PM
5 comments, last by Zorbfish 22 years, 5 months ago

  
#define WIN32_LEAN_AND_MEAN
#define WORLDX    40
#define WORLDY    40
#define SCREENX   20
#define SCREENY   15
#define UP        0
#define RIGHT     1
#define DOWN      2
#define LEFT      3

#define KEYSTATE(key) ((GetAsyncKeyState(key) & 0x8000) ? TRUE : FALSE)

#include <stdio.h>
#include <windows.h>
#include <windowsx.h>
#include <ddraw.h>

class CCamera{
public:
	int height;
	int width;
	int dx;
	int dy;
	int x,y;
	int maxcamerax,maxcameray;
	DWORD color;
	CCamera();
	void Move(int direction);
};

class CHero{
public:
	int height;
	int width;
	int dx;
	int dy;
	int x,y;
	int tilex,tiley;
	CHero();
	RECT location;
	
};

LPDIRECTDRAW lpDD=NULL;
LPDIRECTDRAWSURFACE lpPrimary=NULL;
LPDIRECTDRAWSURFACE lpBackBuffer=NULL;
LPDIRECTDRAWSURFACE lpSecondary=NULL;
LPDIRECTDRAWSURFACE lpHero=NULL;
LPDIRECTDRAWCLIPPER lpClipper=NULL;
HINSTANCE hInstance;
RECT src,dest;
DDBLTFX ddbltfx;
HDC hdc;
CCamera Camera;
CHero Smiley;
CHero NPC;
RECT Tiles[]={
	{0,0,32,32},
	{32,0,64,32},
	{64,0,96,32}
};
int x=0,y=0,start_x,start_y,end_x,end_y;


//Originally just a fill box but now the class holds the camera coordinates

CCamera::CCamera(){
	height=width=32;
	x=y=320;
	dx=dy=5;
	maxcamerax=((WORLDX-SCREENX)*32)-4;
	maxcameray=((WORLDY-SCREENY)*32)-4;
};

CHero::CHero(){
	height=width=32;
	tilex=2;
	tiley=3;
	x=32;y=10;
	dx=dy=5;
	SetRect(&location,(tilex*32),(tiley*32),(tilex*32)+width,(tiley*32)+height);
};

void CCamera::Move(int direction){
	switch(direction){
	case UP:
		if(Camera.y>4)
			Camera.y-=Camera.dy;
		break;
	case RIGHT:
		if(Camera.x<maxcamerax)
			Camera.x+=Camera.dx;
		break;
	case DOWN:
		if(Camera.y<maxcameray)
			Camera.y+=Camera.dy;
		break;
	case LEFT:
		if(Camera.x>4)
			Camera.x-=Camera.dx;
		break;
	}
};

// excluded map array


long CALLBACK WindowProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam);

// excluded direct draw start up


// excluded bitmap load function


void Draw_Hero(){
	if(Smiley.x<0)
		Smiley.x=0;
	if(Smiley.y<0)
		Smiley.y=0;
	if(Smiley.x>=(640-Smiley.width))
		Smiley.x=(640-Smiley.width);
	if(Smiley.y>=(480-Smiley.height))
		Smiley.y=(480-Smiley.height);
	SetRect(&Smiley.location,(Smiley.tilex*32),(Smiley.tiley*32),(Smiley.tilex*32)+32,(Smiley.tiley*32)+32);
	SetRect(&src,0,0,32,32);
	lpBackBuffer->Blt(&Smiley.location,lpHero,&src,DDBLT_WAIT|DDBLT_KEYSRC,NULL);
}

void UpdateFrame(){
	SetRect(&dest,0,0,32,32);
	int xstart=Camera.x >>5;
	int ystart=Camera.y >>5;
	int xend=xstart+21;
	int yend=ystart+16;
	int xoffset=Camera.x&0x01F;
	int yoffset=Camera.y&0x01F;
	if(!xoffset)
		xend--;
	else
		dest.left-=xoffset;dest.right-=xoffset;
	if(!yoffset)
		yend--;
	else
		dest.top-=yoffset;dest.bottom-=yoffset;
	for(int y=ystart;y<yend;y++){
	for(int x=xstart;x<xend;x++){
		int tile=map[y][x];
		lpBackBuffer->Blt(&dest,lpSecondary,&Tiles[tile],DDBLT_WAIT,NULL);
		dest.left+=32;dest.right+=32;
	}

	dest.top+=32;dest.bottom+=32;dest.left=0-xoffset;dest.right=32-xoffset;
	}
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd){
	MSG msg;
	HWND hwnd;

	WNDCLASS wc;
	wc.style= CS_HREDRAW|CS_VREDRAW;
	wc.hInstance=hInstance;
	wc.lpfnWndProc=WindowProc;
	wc.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
	wc.hCursor=LoadCursor(hInstance,IDC_ARROW);
	wc.hIcon=LoadIcon(hInstance,IDI_APPLICATION);
	wc.cbClsExtra=0;
	wc.cbWndExtra=0;
	wc.lpszClassName="Window";
	wc.lpszMenuName=NULL;

	RegisterClass(&wc);
	hwnd=CreateWindowEx(WS_EX_TOPMOST,"Window","Test",WS_POPUP,0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN),NULL,NULL,hInstance,NULL);
	ShowWindow(hwnd,nShowCmd);
	UpdateWindow(hwnd);
	ShowCursor(FALSE);

	if(FAILED(DirectDraw(hwnd)))
		return FALSE;
	if(FAILED(LoadImage(lpSecondary,"grass.bmp")))
		return FALSE;
	if(FAILED(LoadImage(lpHero,"sprite.bmp")))
		return FALSE;

	ddbltfx.dwSize=sizeof(DDBLTFX);
	ddbltfx.dwFillColor=0;

	while(TRUE){
		DWORD dwStart=GetTickCount();

		if(KEYSTATE(VK_UP))
			Smiley.y-=Smiley.dy;
		if(KEYSTATE(VK_ESCAPE))
			PostQuitMessage(0);
		if(KEYSTATE(VK_DOWN))
			Smiley.y+=Smiley.dy;
		if(KEYSTATE(VK_LEFT))
			Smiley.x-=Smiley.dx;
		if(KEYSTATE(VK_RIGHT))
			Smiley.x+=Smiley.dx;

		if(KEYSTATE(VK_UP) && Smiley.y<=120 && Camera.y>4)
		{
			Smiley.dy=0;
			Camera.Move(UP);
		}
		else if(KEYSTATE(VK_DOWN) && Smiley.y>=360 && Camera.y<Camera.maxcameray)
		{
			Smiley.dy=0;
			Camera.Move(DOWN);
		}
		else
		{
			Smiley.dy=5;
		}

		if(KEYSTATE(VK_LEFT) && Smiley.x<=120 && Camera.x>4)
		{
			Smiley.dx=0;
			Camera.Move(LEFT);
		}
		else if(KEYSTATE(VK_RIGHT) && Smiley.x>=480 && Camera.x<Camera.maxcamerax)
		{
			Smiley.dx=0;
			Camera.Move(RIGHT);
		}
		else
		{;
			Smiley.dx=5;
		}
		if(KEYSTATE(VK_ESCAPE))
		{
			PostQuitMessage(0);
		}

		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)){
			if(msg.message == WM_QUIT){
				break;
			}
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}

			UpdateFrame();
			Draw_Hero();
			lpPrimary->Flip(NULL,DDFLIP_WAIT);

	};
	return msg.wParam;
};

long CALLBACK WindowProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam){
	PAINTSTRUCT ps;

	switch(message){
	case WM_ACTIVATEAPP:
		break;
	case WM_PAINT:
		BeginPaint(hwnd,&ps);
		EndPaint(hwnd,&ps);
		break;
	case WM_DESTROY:
		if(lpDD!=NULL){
			if(lpPrimary!=NULL){
				if(lpBackBuffer!=NULL)
					lpBackBuffer->Release();
				if(lpClipper!=NULL)
					lpClipper->Release();
				if(lpSecondary!=NULL)
					lpSecondary->Release();
				if(lpHero!=NULL)
					lpHero->Release();
				lpPrimary->Release();
			};
			lpDD->Release();
			lpBackBuffer=NULL;
			lpClipper=NULL;
			lpSecondary=NULL;
			lpPrimary=NULL;
			lpDD=NULL;

		};
		ShowCursor(TRUE);
		PostQuitMessage(0);
		break;
	default:
		break;
	};
	return DefWindowProc(hwnd,message,wParam,lParam);
};  
Using my current code I finally got a smooth scrolling tile engine in the works. I have setup two classes; camera and hero. The hero is the player and they have 8-way movement and the camera will scroll when the player reaches a set border from the screen (sort of Secret of Mana style)... I''ve played around a bit trying to get a stationary npc to exist in my world but I cannot get it to stay in place.. instead it seems to just paste itself to the screen and stay there as the camera scrolls... I was told that I have to set world coordinates and then convert them to draw coordinates when the npc comes into the player''s viewpoint. Can anyone explain or show me more to this??? Thanks in advance, Zorb
You need to combine the camera x and y coordinates. That means, to get the position of the npc on the screen, you need to do this:
screen_x_position+npc_x_position
and the same thing for y.
That way, if the screen x position is 0, and the npc x position is 50, they''re drawn at x position 50. If the npc is still at 50 and the camera position is -25, the npc is drawn at 25.

Hope this clears things up...
-Arek the Absolute
-Arek the Absolute"The full quartet is pirates, ninjas, zombies, and robots. Create a game which involves all four, and you risk being blinded by the sheer level of coolness involved." - Superpig
Advertisement
Normally you would anchor your camera to your hero, that way you are actually moving your hero not the camera itself. The same principle applies to your NPC''s, they have a position (fine coords) just like your hero. To get them to stay on screen when the hero is moving, move them by the same amount in the same direction.


,Jay
Yes I do realize most games anchor the camera... but I want to try and give the player more freedom and be less restricted to grided movement. I do realize that using this will make coding more complicated but I have lots of time on my hands.
Also wouldn''t it be the camera coordinates are subtracted from the npc position? Because if the object resides at (400,50) and the camera was at (250,0) the npc wouldn''t be on the screen. The result would be (650,50) which is out of bounds of my set screen: (640,480,32). 250*32=8000 pixels and I believe that (400,50) would be within that range...
If you store your npc''s/heros position as fine coords then you get complete freedom of movment even when achoring the camera.

Thats why your draw routines use a tileX and offsetX.

(TileX*TileWidth)+OffsetX = Fine Coord X

What I meant by moving NPC''s with respect to your camera/hero is that if a NPC is at 100,100 and your camera at 0,0. If you then move your camera by 200 pixels right your npc move off the screen, if you add 200 pixels to your NPC it seems to stay in place (with respect to the viewport).

But yes, you need to draw your NPC by using NPCX-CameraX =ScreenX.

Your screen is basicly just a viewport (window) onto the world you are creating.

,Jay
Despite my best efforts... I lost my tile engine code when my computer crashed a few days ago... Luckily I had posted it all above (and in another post) and I recoded it into my project, only there''s one problem.... for some reason it crawls... as if its hanging up somewhere in the code.... It didn''t do this before when I wrote it but there''s no changes... could I have some build-up in memory or ram from it causing it to slow the program down???? I really have no idea what''s up with it...
Advertisement
Ah, nevermind I found the problem... I had written 32 bit resolution and not 16 bit... now it runs nice and smooth.. But that raises another question of mine: why such a dramatic difference in performance when changing from 32 to 16 bit???

This topic is closed to new replies.

Advertisement