Programming Guidance

Started by
1 comment, last by rpg gamer 17 14 years, 5 months ago
Language: C++ Compiler/IDE: MSV C++ 2008 Using: SDL, SDL_TTF, SDL_Mixer, SDL_Image I am trying to use Model, Behavior, Movement: Model - Will handle Loading, Clipping, Animating of the Object Behavior - Will handle AI Movement - Will handle pathfinding, collision detection, positioning I am having a hard time figuring out how to set up the GObjects. Here is the class:

#pragma once

#include <iostream>
#include "GOBase.h"
#include "Model.h"
#include "Behavior.h"
#include "Movement.h"

class GObject
{
public:
	Model* mModel;
	Behavior* mBehavior;
	Movement* mMovement;
	GObject(Model* model, Behavior* behavior, Movement* movement);
	void Init(void); //Handles Model
	void Update(void); //Handles Behavior
	void Render(void); //Handles Movement
	void MousePressed(const int &B, const int &x, const int &y, const int &xRel, const int &yRel);
	void MouseReleased(const int &B, const int &x, const int &y, const int &xRel, const int &yRel);
	void MouseMove(const int &x, const int &y, const int &xRel, const int &yRel);
	~GObject(void);
};
GObject::GObject(Model* model, Behavior* behavior, Movement* movement)
{
	mModel = model;
	mBehavior = behavior;
	mMovement = movement;
}
void GObject::Init(void)
{
	mModel->Init();
	mBehavior->Init();
	mMovement->Init();
}
void GObject::Update(void)
{
	//I D K
}
void GObject::Render(void)
{
	//I D K
}
void GObject::MousePressed(const int &B, const int &x, const int &y, const int &xRel, const int &yRel)
{
	mModel->ButtonMousePressed(B, x, y, xRel, yRel);
	mBehavior->ButtonMousePressed(B, x, y, xRel, yRel);
	mMovement->ButtonMousePressed(B, x, y, xRel, yRel);
}
void GObject::MouseReleased(const int &B, const int &x, const int &y, const int &xRel, const int &yRel)
{
	mModel->ButtonMouseReleased(B, x, y, xRel, yRel);
	mBehavior->ButtonMouseReleased(B, x, y, xRel, yRel);
	mMovement->ButtonMouseReleased(B, x, y, xRel, yRel);
}
void GObject::MouseMove(const int &x, const int &y, const int &xRel, const int &yRel)
{
	mModel->ButtonMouseMove(x, y, xRel, yRel);
	mBehavior->ButtonMouseMove(x, y, xRel, yRel);
	mMovement->ButtonMouseMove(x, y, xRel, yRel);
}
GObject::~GObject(void)
{
}



My questions are at the bottom. NOTE: Model, Behavior, Movement are blank classes except for the ones called in this post. They will not be shown; I will however show a GOBase class that is inherited by Model, Behavior, Movement. This class shows several functions called in the above source code.

#pragma once

#include <iostream>
#include <SDL.h>
#include <SDL_image.h>
#include <string>
#include <vector>

struct GOButton; //Holds button position data
class GOBase
{
private:
	short int OnList;
	//button variables:
	std::vector<GOButton> ButtonList;
	short int lastBNumber;
	short int BNumber;
	std::string ValueReturned; //value of current clicked button
	bool DeleteDead;
public:
	bool Initialized;
	GOBase(void);
	virtual bool Init(void);
	virtual void Update(void);
	virtual ~GOBase(void);
	bool HasButton(void);
	void CreateButton(unsigned int x, int unsigned y, unsigned int w, unsigned  int h, std::string ReturnValue);
	void LoadButtonImage(std::string filename, unsigned short int State);
	void LoadButtonColor(unsigned short int State, int r, int g, int b);
	void ButtonMousePressed(const int &B, const int &x, const int &y, const int &xRel, const int &yRel);
	void ButtonMouseReleased(const int &B, const int &x, const int &y, const int &xRel, const int &yRel);
	void ButtonMouseMove(const int &x, const int &y, const int &xRel, const int &yRel);
	void RenderButton(void); //called in update function of Model, Behavior, Movement
	void CleanButton(void); //check for dead buttons and delete them from the list and memory **Incomplete**
};

struct GOButton
{
	bool isPressed;
	int x;
	int y;
	int w;
	int h;
	SDL_Surface* Image[4]; //0 - Mouse not over, 1 - Mouse Over, 2 - Mouse Pressed, 3 - Selected
	short int State; //-1 - Dead, 0 - Mouse not over, 1 - Mouse Over, 2 - Mouse Held, 3 - Selected
	std::string ReturnValue;
	GOButton(void)
	{
		State = 0;
		isPressed = false;
		x = 0;
		y = 0;
		w = 0;
		h = 0;
		for(int v = 0; v < 4; v++)
			Image[v] = NULL;
	}
};

GOBase::GOBase(void)
{
	Initialized = false;
	lastBNumber = 0;
	BNumber = 0;
	DeleteDead = false;
	OnList = -1;
	ValueReturned = "";
}
bool GOBase::Init(void)
{
	return true;
}
void GOBase::Update(void)
{
}
void GOBase::Render(void)
{
}
bool GOBase::HasButton(void)
{
	return !ButtonList.empty();
}
void GOBase::CreateButton(unsigned int x, int unsigned y, unsigned int w, unsigned  int h, std::string ReturnValue)
{
	lastBNumber = BNumber;
	GOButton temp;
	temp.ReturnValue = ReturnValue;
	temp.x = x;
	temp.y = y;
	temp.w = w;
	temp.h = h;
	ButtonList.push_back(temp);
	BNumber++;
}
void GOBase::LoadButtonImage(std::string filename, unsigned short int State)
{
	if(!ButtonList.empty())
	{	
		SDL_Surface* temp = IMG_Load(filename.c_str());
		if(temp != NULL)
		{
			ButtonList[lastBNumber].Image[State] = SDL_DisplayFormat(temp);
			SDL_FreeSurface(temp);
		}
	}
}
void GOBase::LoadButtonColor(unsigned short int State, int r, int g, int b)
{
	if(HasButton())
	{
		ButtonList[lastBNumber].Image[State] = SDL_CreateRGBSurface(SDL_GetVideoSurface()->flags, ButtonList[lastBNumber].w, ButtonList[lastBNumber].h, 32, 0, 0, 0, 0);
		if(ButtonList[lastBNumber].Image[State] != NULL)
		{
			SDL_FillRect(ButtonList[lastBNumber].Image[State],
				&ButtonList[lastBNumber].Image[State]->clip_rect,
				SDL_MapRGB(ButtonList[lastBNumber].Image[State]->format, r, g, b));
		}
	}
}
void GOBase::ButtonMousePressed(const int &B, const int &x, const int &y, const int &xRel, const int &yRel)
{
	if(HasButton())
	{
		GOButton temp;
		if(B == SDL_BUTTON_LEFT)
			for(std::vector<GOButton>::iterator ButtonIt = ButtonList.begin(); ButtonIt != ButtonList.end(); ButtonIt++)
			{
				temp = *ButtonIt;
				if(x > temp.x && x < temp.x+temp.w && y > temp.y && y < temp.y+temp.h)
				{
					ValueReturned = temp.ReturnValue;
					ButtonIt->State = 2; //pressed
					ButtonIt->isPressed = !ButtonIt->isPressed;
				}
			}
	}
}
void GOBase::ButtonMouseReleased(const int &B, const int &x, const int &y, const int &xRel, const int &yRel)
{
	if(HasButton())
	{
		GOButton temp;
		if(B == SDL_BUTTON_LEFT)
			for(std::vector<GOButton>::iterator ButtonIt = ButtonList.begin(); ButtonIt != ButtonList.end(); ButtonIt++)
			{
				temp = *ButtonIt;
				if(x > temp.x && x < temp.x+temp.w && y > temp.y && y < temp.y+temp.h)
				{
					ValueReturned = "";
					if(temp.Image[3] == NULL)
					{
						ButtonIt->State = 1; //over
						ButtonIt->isPressed = !ButtonIt->isPressed;
					}
					else
					{
						ButtonIt->State = 3; //selected
					}
				}
			}
	}
}
void GOBase::ButtonMouseMove(const int &x, const int &y, const int &xRel, const int &yRel)
{
	if(HasButton())
	{
		GOButton temp;
		for(std::vector<GOButton>::iterator ButtonIt = ButtonList.begin(); ButtonIt != ButtonList.end(); ButtonIt++)
		{
			temp = *ButtonIt;
			if(x > temp.x && x < temp.x+temp.w && y > temp.y && y < temp.y+temp.h)
			{
				if(!temp.isPressed)
				{
					ValueReturned = "";
					ButtonIt->State = 1; //over
					ButtonIt->isPressed = false;
				}
			}
			else
			{
				if(!temp.isPressed)
				{
					ButtonIt->State = 0; //not over
				}
			}
		}
	}
}
void GOBase::RenderButton(void)
{
	if(HasButton())
	{
		SDL_Rect offset;
		GOButton temp;
		for(std::vector<GOButton>::iterator ButtonIt = ButtonList.begin(); ButtonIt != ButtonList.end(); ButtonIt++)
		{
			temp = *ButtonIt;
			offset.x = temp.x;
			offset.y = temp.y;
			SDL_BlitSurface(temp.Image[temp.State], &temp.Image[temp.State]->clip_rect, SDL_GetVideoSurface(), &offset);
		}
	}
}
GOBase::~GOBase(void)
{
}



First Off: I created GOBase so that I can create Object specific buttons and receive the state of the button from it. If you looked through the GObject class, you might of noticed //I D K in the Update and Render function. I don't know what to put here. I know I'm going to have to call the Update function of Model, Behavior, Movement somewhere. That is a given. How would I update what animation Model should show and what direction Movement should travail? I'm guessing Behavior is going to be used to decide these. I want to use Render to show the images. How would I get which image and text to show and where I should show them? What should I add to GOBase functionality? Thank you. NOTE: Model, Behavior, Movement are blank classes except for the ones called in this post. Today is the day I create the structure of the classes. I will not set this in stone so if you wish to recommend something I am open to new ideas. I will have more questions after I get the updating of Model, Behavior, Movement planned out and working properly. [Edited by - rpg gamer 17 on October 30, 2009 4:20:46 PM]
-----------------------------I heard the voice of the fourth beast say, Come and see.And I looked, and behold a pale horse: and his name that sat on him was Death, and Hell followed with him. And power was given unto them over the fourth part of the earth, to kill with sword, and with hunger, and with death, and with the beasts of the earth.Revelation 6:7-8 (King James Version)
Advertisement
Given the current layout you've provided, in your Update() method I'd recommend you call the behavioural updating code first, this where you will set a bunch of flags such as movement direction. The behaviour will be different whether the object is player or AI controlled. The AI will run over a bunch of flags and consider a bunch of conditions and then determine what it should do. You would usually use a state machine for this sort of functionality, once the AI decides what to do the AI is said to be put in a certain state. As a part of the state the AI might decide it is walking forward, and as such you would set a flag telling the object to walk forward.

For a player in the behaviour section you might check for input, or you might have a separate input manager that sets a bunch of flags for the player. For example when the player is holding "W" or Up you might set the forward movement flag.

Once you've established the movement flag (or desired movement flag) you can do a bunch tests to ensure the moment is actually logical, i.e. Ray cast. If the player is up against a wall you probably don't want them to try and walk into it. If you don't check for this here in the behaviour section the model would animate as if it was walking but it wouldn't move at all because it's stuck against a wall, this way the model want actually try to walk.

At either the end of the behaviour section you can apply a movement force and also set the animation the model will perform based on the characters final movement flags.

I would probably have a separate method for movement so all objects get to run their behaviour before the world starts to physically update. In the movement section you would want to convert objects force and velocity to a resulting velocity and apply any translations to the model.

In the movement method you'd probably also want update the models skeleton based on the amount of time that has elapsed and the currently playing animation.

If done correctly you could make rendering run on a completely different thread. The rendering should only need to render the model's altered mesh (based on the bone positions) in 3D space based on the 3D transform that was changed in the movement section.

EDIT: Collision detection and such would occur in the movement phase. You first move all object to their desired 3D position and orientation, if in doing so they passed through each other you would have to solve the collision based on a bunch of constraints. This can actually be quite complex and you'll have to read up about this and physics in detail.
The game is 2D. I will be attempting 3D when I get a solid grasp of 2D design. I will be creating the same project I'm attempting now in 3D when I do.

You said a state machine.
I tried this in a recent project and failed. I'll experiment with sending states to GObject from the Model, Behavior, Movement class and then to the desired locations.

The state machine idea gave me this:
enum eState {NOTHING,WALK_LEFT, WALK_RIGHT, WALK_UP, WALK_DOWN, WORKING};//working will be changed and more flags will be added later.struct GOState{	//From Model To Render()	SDL_Surface* ShowMe;	SDL_Rect Clip;	//From Behavior To Model & Movement	eState State;	//From Movement To Render()	unsigned int x;	unsigned int y;	unsigned int GridPosition;	GOState(void)	{		State = NOTHING;		ShowMe = NULL;		x = 0;		y = 0;		GridPosition = 0; //I D K	}};

This is not set in stone.

I wasn't thinking about which should be first. I guess that would make sense to have behavior first.
You said force and velocity this got me thinking about my next task; The Grid/Node System.
I haven't got to mess around with Nodes and pathfinding. This is really what this project is all about. I get the general idea of A* and I will look back over several tutorial before attempting it.
I have one issue on the subject of path-finding that I wish to discuss.

Q1: What should be in a Node?

I can't really answer this unless I know a little about my project(notice the I's).
Here is the basic concept and plan of this project:
The player can create buildings of a set size and type and place them on the Grid. Each building will have different jobs. Some will require an employee to walk from spot to spot and play an animation; Some will remove the employee from the players view; Some will require the person to walk from building to building and retrieve something(1*). The employees(people) handle there task the building has for them. The building will have a maintenance cost, and an income. Every building will pay there workers an edit-able wage(2*). I want the buildings to have entrances, over hangs, walls, and unbuildable spots(3*) surrounding the building.

(1*)Workers will have to fill a cart and tell haulers to move it to the docks for shipping.
(2*)One reason for the button functionality in GOBase.
(3*)These are to insure a person can enter the building. They will be considered 'path tiles' and be more likely to be taken as a route to a location.

Note: All of the buildings are going to be more than 1 Node wide.

Q2: How would I determine which Node is what building?

The people will have to communicate with the building that it is employied to. The behavior of the building is to update the location and animation for the employee to walk to and do while working. The employee will collect the building updates if the person feels up to it.

Q3: About 'force' and velocity, this force would be something I could use for an object to be able to move the cart object mentioned in the first (1*), right?

Thank You
For All Help Offered.

[Edited by - rpg gamer 17 on October 30, 2009 11:53:54 PM]
-----------------------------I heard the voice of the fourth beast say, Come and see.And I looked, and behold a pale horse: and his name that sat on him was Death, and Hell followed with him. And power was given unto them over the fourth part of the earth, to kill with sword, and with hunger, and with death, and with the beasts of the earth.Revelation 6:7-8 (King James Version)

This topic is closed to new replies.

Advertisement