Jump to content

Rick

Members
  • Posts

    7,936
  • Joined

  • Last visited

Everything posted by Rick

  1. ?? not following what you mean. If you mean LEO and then normal LE, LEO seems to just be an "unofficial" C++ interface to the normal LE commands. We are all using the same C/C++. Don't confuse visual studio with C++. They are different.
  2. Just curious, not trying to be condescending or anything, but does BMax allow you to compile dynamically like .NET does? In .NET one can compile scripts while the main program is running into the main program and then run the code.
  3. The way that guy is doing his communication between components is by storing actual derived component pointers in other component classes. Doing it this way wouldn't be bloated but it's not a good separation either since you actually store a pointer to the child component objects within other components. Then he's passing them in constructors or with set methods. This completely goes against decoupling which could be looked at as one of the main reasons for even doing this design. In order to make the "correct" separation "bloat" needs to be added to how components work. Like in my example above there is "bloat" to allow components to get other components without directly including a specific derived component. Then an event system is implemented in order for components to communicate between each other without knowing the specific derived component type. This can be looked at as "bloat" also. If we followed that website the components aren't really plug and play because they are looking specifically for certain types. With the "bloated" design types aren't needed and only string keys are required. Both for components and events. That helps make the components decoupled as I could use 3 different components as long as I identify them with the same name and they have the same events. The actual class name to all 3 could be completely different and the method I use above still works. If we use the approach of communication that website uses and I use a different component from someone else that kind of does the same thing as others, I would have to go into my components class and change the type name and include that types header. Let's say you, me, and tyler all create a FPSMovement component. We each implement different features like maybe you have head bobbing, tyler has ducking, and I have peaking around corners. You call your actual component class FPSHeadBobComponent, tyler calls his FPSDuckComponent, and I call mine FTPCornerPeakComponent. Now I have a component that needs data from a FPS movement type component. With the websites method I would have to go into my component that requires this FPS stuff and edit the type so I can get your specific instance or each one. That's not really the idea behind component design so that's a no no. Ideally you shouldn't have to alter the insides of your component just because it's using a different class component. That's possible with the design I have above as long as each different instance exposes the same interface (or events/attribtues). So in the example of our 3 different style classes, I can have all 3 in my project and just plug and play any one to a game object and as long as they all 3 are identified with the same string name, it'll work. Taking the example above one could make a separate disoriented FPS movement that happens after a flashbang goes off. As long as the interface between that and the normal fps control are the same, one could swap these components when the flashbang goes off on the fly and all components that have a reliance on the fps movement component will continue to work. Swapping on the fly like this is pretty cool. You could have many different behaviors that get swapped on the fly like this. Think of flying controls compared to fps walking controls. You can have 2 separate components to handle both, and as long as the events between them are the same and the name of each is the same, you can swap these components in and out of a game object based on if you are flying or on the ground and everything will continue to work in stride. That's amazing separation because now you don't have to have 1 main movement component that has to branch off logic based on what it's doing. The game object that has these components can now control what components it needs on the fly.
  4. wowser!! Although the OP is clearly misguided it never amazes me how far some people go when something they like gets insulted. That one was pretty far. As far as the OP language argument goes I would assume he meant AAA games, which he's mostly correct. However there are many levels of games making money below AAA. However, seeing how one can program with the engine in C/C++ it should really not mean much at all what it's created in. It's well known, at least I think it is, that LE is geared towards higher end machines (currently), so performance has little to do with BMax and more to do with the features LE supports. This is pretty much the case in basically any engine out there. Even with things like UDK, sure it might be easy to get pretty pictures up, but most non programmers would probably end up saying what you are saying when it comes to getting the game logic put in. Overall it sounds more like frustration on the OP part with maybe realizing that a ton of work is required to make a game, and the amount of work can be helped by only very expensive engines, which most of us can't afford. Maybe he's just taking it out on LE.
  5. That's what I have above also. All a component has to call is GetComponent(component_name) and it'll find any component attached to the "game object" that that component is also attached to and return it. Yeah, with that system you'd have to include the headers of those classes in C++ into those components since you are using the type name. That's not decoupled enough I don't think. Events or virtual methods part of the Components class seem to really be the only way to keep these components "unknown" to each other. I prefer events since I think it's easier than having 1 giant switch in an OnMessage() virtual method, although the only issue with events is that there needs to be a way for components to bind to other components events and that can't happen until all components are added. I have solved that above, but I don't like it since if CheckDependencies() gets called more than once it can cause multiple binding of events. I might have to go to an OnMessage() virtual method, but not all that thrilled about that. I could also work out a way to see if a event handler is already bound and if so don't bind again. Haven't tried doing that before with the event system. Might be able to compare function pointers or something. I do agree with this also, but I'm hoping that it pays off in the long run. I can vouch for the problem they say this design solves though. To many times have I got a good hierarchy structure and then want to make a gameplay design change when I'm 1/2 way in and realize that it's going to be a major overhaul or hack city and just lost interest in the game. This seems like it'll solve that.
  6. I've found that game objects talking to each other and knowing about each other is always a problem with most every system. There seems to be a few ways to handle this and some I would consider better than others, but might be somewhat more complex. For example I would consider objects sending events the best solution but it's more complex than having all game objects global. If one class tries to access a global object and then you take that objects away for some reason things start to break. I like events because objects that need to care about events are responsible for registering for them, and the registration can be done in the "outside world" instead of pointers being stored from within objects to other specific objects. My solution above was to use events (that have a common signature) and to have components query for other components, that are attached with the game object, that they wish to bind to an event it has. So the RespawnComponent binds to the OnDeath event from the HealthComponent so it knows when the health is <= 0. From within the RespawnComponent it doesn't need to reference HealthComponent directly. Instead it can query for the HealthComponent but return it's Component only and then bind to the even. This requires knowing the names of events that a specific component creates. I think easier helper functions within Component can make this easier for component makers.
  7. Rick

    set zip password

    I get the same Zip data error if I do that. I would assume as long as I call this before it tries to access anything in the zip/pak file I would be fine. I call this right after Graphics() is set.
  8. If I set a password to a pak file, how can I have my program read the data in these files? I've tried SetZipStreamPassword("abstract::pak_file_here.pak", "my_pw_here") but couldn't get it to work.
  9. That's pretty cool. I assume you are using OpenGL then if not LE?
  10. When I picture this system I always picture the building of an actual game from an editor where the components have been built already (or new components can be added). Where designers drag and drop components that programmers have built to make game objects functional. I drop the base level model into my scene. I then drop the pathfinding component on it that builds a navmesh. I then drop an empty game object into the scene. Attach an alient model component. Attach an AIPathFinder component on it and now it'll work with the level pathfinding component to be able to find paths. Add a controller component and now it can move along the paths it finds. Add a PlayerSeeker component and now it'll wonder around looking for the "player". The components become the building blocks for designers to make games. It probably sounds a lot like a FPS creator, but when you have control to code components it's not limiting at all. All game objects would know about each other because a game object is just a component and every "game object component" is derived from 1 master component, so there is a parent tree that can be climbed by any child component to find any other "game object component". That's why there are 2 AddComponent() methods. One allows you to give a name instead of a component type. So in any other component, like the PlayerSeekComponent example above, it can simply do GetComponent("player") and it'll transverse the tree automatically to find the player component and can then know everything it wants to about the player component. To me that's very cool. In a class based system getting information about other classes can start to get messy normally. Are you passing tons of variables around, or storing pointers to them in other classes, or making them global. I've used all those methods and it's a pain. When your design changes you often end up changing what needs to be seen by what, until each class has a ton of pointers to objects, or you end up passing a ton of objects to functions, or everything becomes global/singleton. Those methods suck I think I would find it nice to be able to easily query any component at any time from within any other component. If only the syntax didn't suck so much [edit] Another feature about this I think would be that after awhile you would have a nice component library and basic reusable components would be so plug and play in any game you make with 0 alteration required since they are all self containing. For the most part any complex hierarchy structure generally takes some tweaking/slamming in to get working with multiple projects.
  11. The interesting thing that I read about this pattern is that most everyone says that. I think one article said that we have become very good at learning to deal with the downfalls of a messy hierarchy structure because in any relatively large game (for the most part) things start to get large and almost unmanageable with a deep hierarchy. Requirements change (as they always do) and suddenly we realize our perfect design starts to fall apart or get unmanageable because of maybe some hacks or what have you. I've ran into this and I was only making smaller games. You get your perfect hierarchy design down, start coding away, then a new(er) game design idea hits you. You look at what it takes to implement into the hierarchy design you have and either you refactor a ton of code or you hack it in. Most of the time this is where things get either boring or frustrating. I agree that the properties method looks ugly (not sure much can be done about that in C++) and most likely works better with languages like lua where you can just create a variable that can hold anything anytime. However, this approach is more flexible. This allows me to create variables from outside sources like a config file without recompiling. Flexibility is the name of the game for this pattern. The thing I really enjoy about this is that it seems to be great for sharing code and working on projects with larger teams (if you can convince other programmers to use it). The syntax I have is something I put together in a day or so. I might be able to make it little less intrusive. I think the communication between components is where the trouble starts. My first attempt is what you see above with using an event system. Virtual methods could be used like OnMessage() (which I have but didn't use). I'm not a fan of use switch statements in a catch all message function myself. I'll see what I can do about component & attribute access.
  12. So just playing around with different design patterns. I've read, and experience, that deep class hierarchy systems become bloated and not very flexible. As things change tons of hacks end up being put in and classes get stuff they don't need. So the Component design is supposed to help with that by using containment rather than inheritance. That's kind of the idea behind the Component design, but to make that idea generic so it can be used as almost a framework get's interesting. Anyway I'll show how one would use it first, then how the code behind the magic (if you call it that) works. Interested in thoughts/ideas/concerns/potato chips? The main test program: Very simplistic idea with heavy comments int main() { // we are treating this as the main top level component that stores all other game object type components like // players, zombie, ammo crates, etc. each component added will be able to get this owner so it can search // for all other game object component's loaded. this provides an easy way for enemies to query things about // the player for example Component _gameObjects; // make a generic game object component Component obj1; // _gameObjects becomes obj1's owner automatically by adding a component to it _gameObjects.AddComponent(&obj1, "player"); // add just the components you need for the player to work and after all added check the component dependencies // to make sure they all fit obj1.AddComponent(new HealthComponent()); obj1.AddComponent(new RespawnComponent()); // currently multiple calls to CheckDependencies() could be dangerous since events can get bound in there if(!obj1.CheckDependencies()) { // todo: report a dependency not met somewhere int i = 0; } // testing different ways to get components and attributes //========================================================= // this is how we can get specific components from game objects or generic components Component* healthCompGeneric = obj1.GetComponent("HealthComponent"); HealthComponent* healthComp = obj1.GetComponent<HealthComponent>("HealthComponent"); // this is how we can get attributes from specific components or generic components Attribute<float>* health = healthComp->GetAttribute<float>("health"); Attribute<float>* health1 = healthCompGeneric->GetAttribute<float>("health"); // or we can do it this way //float health1 = obj1.GetComponentAttribute<HealthComponent,float>("HealthComponent", "health"); // below is just for testing purposes to see events fire _gameObjects.OnUpdate(); health->Value = -5; _gameObjects.OnUpdate(); _gameObjects.OnUpdate(); return 0; } The HealthComponent: Used to store a health value and track other health related things like death. class HealthComponent : public Component { private: void RespawnComponent_OnRespawn(Component& c, Message& m) { // we've respawned!! set our health back to the base health value GetAttribute<float>("health")->Value = GetAttribute<float>("base.health")->Value; } public: HealthComponent() { AddAttribute("health", new Attribute<float>(100.0)); AddAttribute("base.health", new Attribute<float>(100.0)); // create an OnDeath event that we can fire and inform other components attached to a game object that // this game object is "dead" CreateEvent("OnDeath"); } virtual void OnUpdate() { // this component will fire the OnDeath event to anyone listening when health is <= 0 if(GetAttribute<float>("health")->Value <= 0) FindEvent("OnDeath")->Raise(*this, Message()); } virtual void OnMessage(int msg){} virtual bool CheckDependencies() { if(!Component::CheckDependencies()) return false; Component* respawn = GetComponent("RespawnComponent"); if(respawn == 0) return false; else // bind to the respawn event so we can reset ourselves respawn->FindEvent("OnRespawn")->Bind(this, &HealthComponent::RespawnComponent_OnRespawn); return true; } virtual string Type() { return "HealthComponent"; } }; The RespawnComponent: Controls respawning of game obejcts class RespawnComponent : public Component { private: bool _dead; void HealthComponent_OnDeath(Component& c, Message& m) { _dead = true; } public: RespawnComponent() { _dead = false; CreateEvent("OnRespawn"); } virtual void OnUpdate() { if(_dead) { _dead = false; FindEvent("OnRespawn")->Raise(*this, Message()); } } virtual void OnMessage(int msg){} virtual bool CheckDependencies() { // check any child dependencies I have to make sure they are good if(!Component::CheckDependencies()) return false; // I care about the health component because when it fires it's OnDeath message I need to start my repsawn // timer Component* health = GetComponent("HealthComponent"); if(health == 0) return false; else // bind to the OnDeath event if this game object has the HealthComponent attached to it health->FindEvent("OnDeath")->Bind(this, &RespawnComponent::HealthComponent_OnDeath); return true; } virtual string Type() { return "RespawnComponent"; } }; The implementation ================== Events.h : You can ignore figuring this out if you like and just use it. Much easier to use than read #pragma once #define events private; #include <list> using namespace std; template<class P, class Q> class TFunctor2 { public: virtual void Call(P var1, Q var2)=0; }; template <class TClass, class param1, class param2> class TSpecificFunctor2 : public TFunctor2<param1, param2> { private: void (TClass::*fpt)(param1, param2); TClass* pt2Object; public: TSpecificFunctor2(TClass* _pt2Object, void(TClass::*_fpt)(param1, param2)) { pt2Object = _pt2Object; fpt=_fpt; } virtual void Call(param1 var1, param2 var2) { (*pt2Object.*fpt)(var1, var2); } }; template<class T1, class T2> class Event2 { public: list<TFunctor2<T1, T2>* > mCaller; template<class Target> Event2(Target* t, void (Target::*fnPtr)(T1, T2)) { mCaller.push_back(new TSpecificFunctor2<Target, T1, T2>(t,fnPtr)); } Event2(){} template<class Target> void Bind(Target* t, void (Target::*fnPtr)(T1, T2)) { mCaller.push_back(new TSpecificFunctor2<Target, T1, T2>(t,fnPtr)); } void Raise(T1 V1, T2 V2) { list<TFunctor2<T1, T2>*>::reverse_iterator iter; for (iter = mCaller.rbegin(); iter!= mCaller.rend(); iter++) { (*iter)->Call(V1, V2); } } void Clear() { mCaller.clear(); } }; Component & Attribute: Much easier to use than read class Message { }; class Component; typedef Event2<Component&, Message&> EventHandler; class AttributeType { }; //=================================================== template <typename T> class Attribute : public AttributeType { private: public: T Value; Attribute(T value){ Value = value; } ~Attribute(void){} }; //==================================================== class Component { private: map<string, AttributeType*> _attributes; // a game component can have other game components map<string, Component*> _components; private: map<string, EventHandler*> _events; protected: void CreateEvent(string name) { // make sure an event doesn't already exists if(_events.find(name) == _events.end()) _events[name] = new EventHandler(); } public: Component(void){} ~Component(void){} virtual string Type() { return "Component"; } virtual void OnUpdate() { map<string, Component*>::iterator iter; // toconsider: we might need certain components to update before others for(iter = _components.begin(); iter != _components.end(); iter++) { (*iter).second->OnUpdate(); } } virtual void OnMessage(int msg){} EventHandler* FindEvent(string name) { if(_events.find(name) == _events.end()) return 0; return _events[name]; } virtual bool CheckDependencies() { map<string, Component*>::iterator iter; // check all dependencies of all components added for(iter = _components.begin(); iter != _components.end(); iter++) { if(!(*iter).second->CheckDependencies()) return false; } return true; }; void AddComponent(Component* comp) { // set the parent of the passed in attribute to us comp->AddAttribute("parent", new Attribute<Component*>(this)); // add this component _components[comp->Type()] = comp; } // an alternative way to identify components. this is used for top level components that'll store game object // style components with a different name like "player" void AddComponent(Component* comp, string name) { // set the parent of the passed in attribute to us comp->AddAttribute("parent", new Attribute<Component*>(this)); _components[name] = comp; } // casts the component template <typename T> T* GetComponent(string name) { if(_components.find(name) == _components.end()) { // if we don't have this component see if our parent does Component* parent = GetAttribute<Component*>("parent")->Value; if(parent != 0) return parent->GetComponent<T>(name); else return 0; } return (T*)_components[name]; } // doesn't cast component Component* GetComponent(string name) { if(_components.find(name) == _components.end()) { // if we don't have this component see if our parent does Component* parent = GetAttribute<Component*>("parent")->Value; if(parent != 0) return parent->GetComponent(name); else return 0; } return _components[name]; } template <typename T, typename C> C GetComponentAttribute(string component, string attribute) { // todo: if we don't have this attribute, travel up the "parent" attribute to see if any of our parents have it // make sure the component exists if(_components.find(component) == _components.end()) return 0; T* comp = GetComponent<T>(component); return comp->GetAttribute<C>(attribute)->Value; } //template <typename T> void AddAttribute(string name, AttributeType* att) { // only add the attribute if it doesn't already exist if(_attributes.find(name) == _attributes.end()) _attributes[name] = att; } template <typename T> Attribute<T>* GetAttribute(string name) { // todo: if we don't have this attribute, travel up the "parent" attribute to see if any of our parents have it if(_attributes.find(name) == _attributes.end()) return 0; return reinterpret_cast<Attribute<T>*>(_attributes[name]); } };
  13. From the screenshot you can see that my zombie on the left is giving off light even though the ambient light is set very very low. My main character in the center is fine since it's cool if he does this, but what would be causing my zombie to give off a light like that? Ideally he would be very very hard to see.
  14. You could load them at runtime like you said and make the first one follow a waypoint. If the others are connected via joints, they should then follow the chain link it was jointed to. That would probably create a cool snake effect. Would just need to think about how to make the last one stay connected to the first one. Not sure what would happen if you jointed the last one to both the one in front and the first link when the first link is the thing driving all the others. Would be cool to see it in action though.
  15. I'm not at home so I can't test, but I was thinking about doing it after Animate(), and just let every animation run the code. If it's a looping animation it should be fine because for stuff like moving I use KeyDown(). So if it hits the last frame of the run animation, it'll set the state back to Idle, but at the top of the next cycle, it'll see that the move key is still down and change the state back to walk. But for things like reload I use KeyHit(). So having the code after the Animate() should only affect the one time animations and not the looping animations. I'll see if that's actually the case when i get home I guess
  16. Oh yeah I see what you mean now. I'm just trying to avoid having multiple frame calcs and Animate() methods called. I'll see what I can do. Thanks!
  17. So that works, but I'm trying to figure out why sometimes when I hit a button (like R for reload state) it doesn't play the animation either at all or not all the way through, but sometimes it does. Here is the code that handles the states. If I hit R it should set _lastFrame to 0.0 which should make the animation play all the way, but it doesn't all the time. if(KeyHit(KEY_R)) { // can't move to reload _move = 0.0; _lastFrame = 0.0; _playerState = PlayerState::Reload; } // handle animations based on state float start, end; switch(_playerState) { case PlayerState::Idle: start = 0.0; end = 200.0; break; case PlayerState::Walk: start = 201.0; end = 321.0; break; case PlayerState::Run: start = 322.0; end = 341.0; break; case PlayerState::RunShoot: start = 411.0; end = 430.0; break; case PlayerState::StandShoot: start = 431; end = 446; break; case PlayerState::Reload: start = 447; end = 489; // reloading is just a one shot, so change the state back to idle once we are finished if(_lastFrame > _frame) { _lastFrame = 0.0; _playerState = PlayerState::Idle; } else _lastFrame = _frame; break; } _frame = AppTime() / 30.0; _frame = fmodf(_frame, end - start) + start; Animate(_entity, _frame);
  18. I like using the fmodf like the documentation does for animations. It's simple. My question would be is there a way to tell if the animation has played once using the fmodf way though? Seems like it wraps around, which means simply checking if the frame is >= end doesn't work. I can't really think of a way to handle this using the fmodf way. _frame = AppTime() / 30.0; _frame = fmodf(_frame, end - start) + start; Animate(_entity, _frame); // doesn't work because _frame ends up wrapping and never seems to actually go past the end frame if(_frame >= end) _playerState = PlayerState::Idle;
  19. Rick

    bullet shooting

    ZioRed, Sorry, this is sort of top down view, and I'm not using the mouse to determine where to shoot. The rotation of the character determines the direction, and the distance will just go a range that is slightly outside the camera viewing area. paramecij, good idea. I was looking at LinePick where 2 points are needed, but LinePick will handle shooting directly forward so that should work. Thanks!
  20. I have the swat model from Dexsoft. http://www.dexsoft-games.com/models/swat.html The gun is attached to the model and currently the gun has no bones. I have an idea of how I will handle shooting but curious on what other ideas people have. My plan was to add 2 bones to the model. One right in front of the gun barrel and another directly in front of that one. I'll find these 2 bones from code and by subtracting their positions I'd be able to get the direction the weapon is pointing. Then if I multiply that vector I can get an end point vector for the raycast. So I guess that's my issue. Getting the start and end vectors for the "bullet" fired from the gun.
  21. Rick

    GUI

    Well, I can't find my working exe code. I found the dll I was trying to make and I think I might have the reason why it's not working for you. Right before renderGUI put: // CEGUI rendering glPixelStoref(0x806E, 0); // GL_UNPACK_IMAGE_HEIGHT glPixelStoref(GL_PACK_ROW_LENGTH, 0); glPixelStoref(GL_UNPACK_ROW_LENGTH, 0); System::getSingleton().renderGUI(); That should help you see the GUI.
  22. Rick

    GUI

    When I get home I'll get my working CEGUI example I had and post it here.
  23. Rick

    GUI

    I was able to get CEGUI working and it was pretty simple. I had a project to strip down CEGUI and make a single dll and include that would make it much easier to work with for LE users, but it turned out to be a giant pain. Getting it to work as it is wasn't bad though.
  24. [EDIT] I'll remove my comments to avoid issues, but sounds like Josh has a pretty clear road map planned out here.
  25. Pixel, what would you say your biggest obstacle was? Since you were creating your own editor for the game, it seems like you would have had a large amount of control over what you made Leadwerks do. It clearly shows that you had the ability and desire to make your own things. So if the water wasn't the way you wanted it, (like in the case for Red), then nothing was stopping you from making your own. If you wanted decals, nothing would have stopped you from making your own. So what were the specific issues that you ran into that you couldn't fix yourself within your editor? I can only imagine these would be true bugs that Leadwerks has and not a lack of anything, as you would have just wrote it yourself. If it's just the fear of Josh not supporting any issues you find in the future, then that seems not all that valid as he's said he's not even working on 3.0 and he probably wouldn't be the one programming it anyway. He'd just be the idea man behind it.
×
×
  • Create New...