[C#] Wink2D Engine

Started by winkio, November 09, 2010, 02:58:34 pm

Previous topic - Next topic

winkio

November 09, 2010, 02:58:34 pm Last Edit: December 07, 2010, 03:54:37 am by winkio
So the game dev club at my university is thinking about making an engine in C#.  I was specifically tasked with thinking about how to make a parent class for all game objects, such as characters, enemies, particles, tiles, etc.  The goal is to provide easy access to create complex game objects through a sort of simplified scripting language.  This is my initial idea:

class GameObject has 3 main pieces of information:

1.  string Name - this is mostly for organizational purposes in whatever editor eventually gets made, and it has no influence on the actual game.
2.  Dictionary<string, object> Properties - this will allow the user to create extra variables and properties through the editor that are not hardcoded into the classes.
3.  Dictionary<string, List<string>> Commands - each List<string> value is a list of pseudo-script commands that can be interpreted by the game engine.  There can be many such lists run at different times, such as every frame, on collision, on interaction with a certain type of event, etc.  The condition on which the list is to be run could be represented by the first command in that list.

There are also 3 methods to be implemented:

1.  Update - needed to have a dynamic object.  This will additionally check each list of commands to see if it needs to be processed.
2.  Interact(GameObject o) - interacts with another game object
3.  Process(string command) - processes a command.  Someone will have to build a lot of functionality into this, as it is what interprets the pseudo-script commands.



So, any thoughts? Something obvious (or not so obvious) I'm missing?  Rampant memory leak or speed reduction?

Blizzard

November 09, 2010, 03:30:15 pm #1 Last Edit: November 09, 2010, 03:35:07 pm by Blizzard
Well, there are loads of things that should be considered. If you don't really care for memory, you can leave the string Name attributes. I prefer having a name for all my objects as well, but it can eat away quite some memory if you have a million objects and each has a name of average length of 20 characters (which results in additional 20 MB of memory).

If you want a really good system that uses commands, I suggest that you create appropriate classes for it. Just using strings is alright for a smaller engine, but if you plan it to be extendable, I'd definitely go with additional classes such as Event, Command, etc.

The Properties thing is a good idea for a generic class, but I don't think you need it that much. Sure, it could make things easier and more dynamic but also more prone to bugs and logical errors (such as literally typing mistakes in the strings used as keys). You could use it for a data model or something like that.

As for the methods, not every object really needs an update method. I'll explain this a bit later. Same with Interact. Process sounds like a good idea, but I'm not sure exactly how you want this to work.


The last engine I have worked on is separated into 5 main parts. I have listed 6 parts here, because I never implemented a proper Menu Model.

Part 1: Static Data Model

The Static Data Model is pretty much what one could call a database. If you know RMXP's scripts, then the static model would be pretty much the data classes in the RPG module. Also, this model doesn't need any update method. It's simply unnecessary. A static model should have a base class from which all other classes are derived.

Part 2: Dynamic Data Model

The Dynamic Data Model represents the objects in the game. Those objects should reference Static Data objects which define their basic template data. Those two models will probably have a very similar inheritance structure. These objects should be able to provide an interface to the outside, but they shouldn't be able to actually do much on their own. This model would obviously have to be updated every frame.

Part 3: View Model

These objects should be used to display the Dynamic Data Model. A GUI library would be the closest thing to a View Model. RMXP's sprites would be kind of close to this one, but IMO they are bloated. This is another model that would have to be updated every frame.

Part 4: Menu Model

This one is obvious. Menu objects display information and data and allow the user to interact and change that information and data. From my personal experience to come up with a good Menu Model is difficult. To come up with a good and generic Menu Model is extremely difficult. This is a model that might not require updates all the time, but an update method might still be a good idea.

Part 5: Controller Model

Controllers define and control how Dynamic Data objects behave and interact with each other. They should also handle user interactions. The scenes from RMXP are an alright example. The Sprite classes in RMXP are also Controllers, but they are kind of messed up. IMO a general Controller Model should be separated from a display Controller Model. Another object model that needs to be updated.

Part 6: System Model

There are usually many small classes or general purpose classes that also need to be implemented. I like to call them System objects. Good examples of System classes would be:
Save Game Manager
Game Profile Manager
Scene/Game-Logic Mode Manager
Menu Manager
Map Position (a "Vector2" with x, y or "Vector3" with x, y, z could be used for this, but I had my reasons for a separate class, it's a long story)
Game Data (the object containing all the game data)
Generic Condition
Generic Condition Set
AI Module
Depending on what kind of object it is and what it does, it might or might not required an update method.


In the end, you should adapt your model to suit your needs rather than making an all-purpose engine. Cut down on properties and generic concepts if you don't need them or don't really see yourself actually using them in your engine. They can be just a waste of your time which you could have used to implement features that matter.
To me personally a similar structure was very useful as I was able to reuse loads of it for a new project. I've been working 8 working days on it for now and it's about 70% done. The full game will probably be done within 15 days of work. Sure, it's a quite simple game, but because I was able to define, separate and implement many useful concepts in MB, I already had loads of stuff already finished and ready to go so that this new game will take a ridiculously short amount of time to make. :) If I didn't have all of that, I would have at least required another 15 days and the end result wouldn't have been as nice and systematical as this will be.

EDIT: BTW, I named my namespaces Database, GameObject, Scene and System. I then used a class Base in the first three to define a base object with all the common properties that are required for every object of that model. While Database::Base and GameObject::Base are quite simple, Scene::Base turned out actually quite complex yet not bloated. I was playing with the thought to rename the namespaces to Data and Game just to be able to write shorter, but namespace Game would probably mess with System::Game so I left it all as it was. Just throwing that thought out there. Maybe you can make something out of it.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

winkio

:D Good stuff Blizz.  We have already roughly divided the engine into different parts.  Our divisions were:


  • Base - low-level generic classes (such as game_object)

  • Graphics - self explanatory

  • MathPlus - was going to be named Math, but didn't want to confuse it with system.Math.  Lots of geometry related stuff and higher level math

  • Multiplayer - methods for split-screen, networked play, etc.

  • Physics - methods for creating simple physics, as well as a physics engine

  • Pipeline - used to read and write the file formats for things such as levels, particle effects, etc.

  • TileMap - framework for creating maps containing 2D tiles

  • Screens - used for handling different game screens and menus

  • System - extra stuff, such as input, save data, etc.



As you can see, we divided up based on the different features of a game.  There's some mixing of static and dynamic data, as well as controllers within each division.  Is this method of organization inferior to yours, or would it still work?

And yeah, we want to have an engine that can be used for all sorts of games (fighting, platformer, puzzle, etc.), yet have a lot of genre-specific stuff built in, so that it won't take as long to create a game of a specific type, and we can reuse a lot of code.  So it's supposed to be something like a 10-in-1 engine.  Because once it's finished, the club (of about 30 people) wants to pursue 3 or more projects simultaneously.

Now, back to the analysis of the GameObject class.  How we conceived it was equivalent to the base Dynamic Data Model.  That is why it has update and interact built in.  Other people are working on our equivalents of the other models.  We are going to recombine ideas on Sunday.

Process will function like the Interpreter in RMXP - it takes a command, and then executes it.  Now that I think about it, it will probably need a helper method to take the whole command list at once, because of conditionals and such.  Due to inheritance, it also allows new objects to have new commands (for example, give a Chicken object the Egg command).  It was my idea of a simplification for non-programmers, where in the editor, they could click on an object, and a list of possible commands specific to that object would come up, and then they could just choose one, fill out a form, and be done.  For the implementation in the base class, it would just have simple things like (Add/Remove Property, Set Property, Erase Object, etc.).

Blizzard

November 10, 2010, 02:45:41 am #3 Last Edit: November 10, 2010, 02:47:19 am by Blizzard
I don't think it's inferior at all. It's just different in some aspects, but it's also similar in others. In fact in the last engine I worked on had the 5 parts I mentioned where I coded 4 of them. The GUI part is a library that we made in Cateia (I am currently refactoring the code massively). We also made a high level types library, a geometry types library, a rendering interface library (that works with both DirectX and OpenGL, yay), a font rendering library and an audio library (we released all of them as Open Source libraries). Since we're working in C++, some of those libraries (such as HL-Types) are very useful to make code shorter, more readable and more organized. :) So we have actually more than just the 6 parts, but the 6 parts are a general outline just for the game logic. The rendering engine is a separate part for itself. Audio could be a part in itself as well or it could be included in the System part. It pretty much depends on how you organize things.

As I said, I think the model is quite good. It's good that you have modularized specific parts of the engine. This will allow you to quickly reorganize the models and refactor the code if you find flaws with the current model and come up with a better one. :)

I hope you can learn a lot from working on that engine. :)
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

winkio

November 14, 2010, 07:23:57 pm #4 Last Edit: November 21, 2010, 02:56:48 am by winkio
Well, just had an interesting meeting today.  I was one of the two people that actually put some effort into their part of the engine (the other being the club president).  And the club is getting restructured for next semester, and so focus has switched to that.  End result: the engine is no longer in the club picture, but I'm picking it up as a personal project.

So anyway, I've started making the GUI for the engine, and I'll probably be making posts about that sometime soon.

EDIT:  Well, this is turning out to be really hard, but really fun.  I've made a custom scrolling tabbed document system, sidepanels that display different information and give the user different tools and functions based on what type of file they are editing, and a dynamic layout scheme that organizes all program elements whenever the window is resized, allowing the GUI to run at any resolution.

EDIT:  And sure enough, it was easy to get XNA to render inside the application.  At this rate, I might finish a prototype over winter break :D

Blizzard

Sounds great, winkio! :D

I know what you mean by it being hard. xD Especially when you're doing something like this the first time. New possible problems keep popping into your mind and you have to reconsider the design over and over several times. xD
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

winkio


G_G

Well I think its a tad bit obvious you or whomevers computer that is, name is ryan. Nuff said.

Nice job btw.

ForeverZer0

Quote from: game_guy on November 25, 2010, 08:10:11 pm
Well I think its a tad bit obvious you or whomevers computer that is, name is ryan. Nuff said.

Nice job btw.


You mean his real name isn't "winkio"!? I'm shocked!  8-O
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

winkio

lol, my email address is my last name followed by my first name.  And that's in the Blizz-ABS manual.  So... yeah, I do have a name, and I'm not afraid of people knowing it.

G_G

neither am I. I was just pointing the obvious out :P

ForeverZer0

To get back on subject, this is looking good. Are you releasing it when done?
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

winkio

Ah, but of course!  Why would I put so much work into something, and then not show off the finished product?

But, in terms of being done, it's going to be a while.

Blizzard

HAHA! FILENAME IS NOT! AND YOUR NAME IS RYAN! Ah, wait, you don't mind people knowing your real name. ._.

You should rename to engine to Win2D, though. <3
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

winkio

November 26, 2010, 11:42:28 am #14 Last Edit: December 07, 2010, 03:54:52 am by winkio
Wink is sexier.  And since it's built on top of XNA and .NET, I don't want any additional affiliation with Microsoft and Windows.

EDIT: Okay, I think I'm finally nearing the end of my 5 hour long battle with XNA rendering.  See, XNA doesn't have any built in way to draw a 2D line, or a 2D rectangle, or a 2D triangle, in terms of pixels, like we are used to in the 2D game community.  It's built for 2D sprites, and 3D rendering, so the only way to draw 2D lines, or rectangles, or triangles is to render them in a 3D environment.  Of course, 3D environments are a lot more complex, so I had to get it to draw with the right view and projection matrices, and use rendering effects.  These rendering effects depend on the size of the render area, etc.

Anyways, I can finally draw anything from polygons to ellipses without it lagging like hell.  Now, it's time to put them to use.  Custom Geometries time!

EDIT 2:  The result of a night spent on gridding: Custom tileset grids!
Spoiler: ShowHide

rectangular


isometric


elevated isometric


horizontal hexagonal


diagonal hexagonal



Blizzard

Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

Ryex

as much as I think that costume grids are cool I doubt that you made this feature just for that. what purpose dose this serve in the long run? what incredible feature do you have laying in wait?
I no longer keep up with posts in the forum very well. If you have a question or comment, about my work, or in general I welcome PM's. if you make a post in one of my threads and I don't reply with in a day or two feel free to PM me and point it out to me.<br /><br />DropBox, the best free file syncing service there is.<br />

winkio

making games from different viewpoints.  It doesn't show from the screenshots, but you can define the size of each shape, allowing you to make tiles that actually correspond to doodads or terrain.

Examples of different viewpoints:
Spoiler: ShowHide



ForeverZer0

I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Aqua

Your isometric doesn't seem right to me... o-o
But the rest...
Mmmmmm :3

Subsonic_Noise

I waited this whole time for you to name something "Wink" so I could call it gay, but after seeing those screenshots I don't feel like it anymore. Damn you.

winkio

December 07, 2010, 11:26:21 pm #21 Last Edit: December 29, 2010, 01:40:51 pm by winkio
Quote from: Aqua on December 07, 2010, 03:19:30 pm
Your isometric doesn't seem right to me... o-o


It may seem off because the unit dimensions are 32x48.  I can make any grid whatever dimensions I want with the code I made, so I took screenshots of different tests.  I can make a 32x32 square isometric, and it lines up exactly with the rectangular.

EDIT: YUHHHHSSSS!  Finally implemented ear clipping.  Hooray for concave polygons!
Spoiler: ShowHide


EDIT 2: After writing an excruciating amount of repetitive code, I finally finished intersections between my 11 defined geometries (due to accounting for generics and conglomerates, points, intersection points, and intersection types, that's over 600 methods).  Now that I can select my shapes, time to edit them :D
Spoiler: ShowHide

G_G

D: I can't see whats in the spoilers :(

winkio

So I was trying to come up with a good way to implement undo/redo, since these are very important functions in an editor of any sort, and I settled on this:

I created an Action object with two properties: object[] EList and object[] UList.  I also created a double stack that would allow me to keep track of which actions can be undone and redone.

The Action object also has two methods: Execute and Undo.  Execute executes the action, using Elist to access other objects and take arguments, also saving backup data to UList.  Undo undoes the action, using UList to restore old data.  The Action class is meant to be extended by each individual action such as selection, shape creation, etc.  So, for any functionality that modifies data in the editor, the editor will create an action, set it's parameters, and put it on the stack.

Thoughts?

Ryex

great minds think alike :P. I was considering how to do the same thing in RMPY and came up with a very simaler solution.

a universal Action objects that dose the actual action to act as a frame work. it has a execute and reverse method. subcalssing this object to create actions for spesfic things like editing map data entails editing the execute and reverse methods to to the necessary operations on the data. adding these objects to a stack means that calling the undo operation pulls the action on the top of the undo or redo stack and calls the execute or reverse command then moves the operation to the other stack.

when ever the editor needs to do something it makes an action object of the right type gives it the needed data calls the execute method and places it on the undo stack. who know perhaps I'll make a global action frame work that provides the undo redo interface so all you need to to is create the action object and pass it to the framework. the frame work would execute the action and place it on the stack an undo or redo call the the frame for would make the appropriate actions. I was thinking of creating some sort of action group so that you could make really small actions group them to gather and execute or reverse them all at once (or rather the order they are arranged in the group) the group would sit on the stacks like an action and would have a execute and revers command that looped through it's contents.

the operations entailed might have to be taken in a different way considering that is is c# and my idea is created with python in mind, but the principle should be the same.

I no longer keep up with posts in the forum very well. If you have a question or comment, about my work, or in general I welcome PM's. if you make a post in one of my threads and I don't reply with in a day or two feel free to PM me and point it out to me.<br /><br />DropBox, the best free file syncing service there is.<br />

ForeverZer0

I like the idea of using a stack-based array for efficiency. I'm curious as to how you are storing the Actions, since they will be widely different depending on the action taken. (it may not be as difficult as I'm thinking, keep in my mind I'm still learning C#).
I wasn't aware you could simply initialize a List with a such a generic data type as "object". Can you store different data types in a single array?
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Ryex

only if the list is of the "object" data type
I no longer keep up with posts in the forum very well. If you have a question or comment, about my work, or in general I welcome PM's. if you make a post in one of my threads and I don't reply with in a day or two feel free to PM me and point it out to me.<br /><br />DropBox, the best free file syncing service there is.<br />

Blizzard

And you would have to cast it back before you can do anything with it meaning you would have to know what's inside. I don't recommend that.

@winkio: You're gonna use delegates, aren't you? <3
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

winkio

February 09, 2011, 09:19:49 am #28 Last Edit: February 10, 2011, 11:44:28 am by winkio
No, it was object arrays.  Each class that extends object had their own Properties defined from each array.  For example:

public class PointerVectorGeometryDocumentControlAction : Action
   {
       /// <summary>
       /// Control to apply the action to (EData[0])
       /// </summary>
       public VectorGeometryDocumentControl Control
       {
           get { return (VectorGeometryDocumentControl)EData[0]; }
           set { EData[0] = value; }
       }

       /// <summary>
       /// Click number (EData[1])
       /// </summary>
       public int Click
       {
           get { return (int)EData[1]; }
           set { EData[1] = value; }
       }


In this way, you wouldn't ever access the object arrays directly.  Of course, when doing this, I realized that this is the same thing as just not having the arrays to begin with and simply declaring new properties in each class.  So that's what I ended up doing XD

EDIT: Well now I know my file format is efficient, I just saved a geometry with 20 shapes and it was only 98 1198 bytes :D

Blizzard

Lol, I was already like "98 bytes?! O_O Jesus H. Christ in a chicken basket! O_O"
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

winkio

Yeah, that was an obvious typo.  I'd laugh if I actually was able to store each shape object in 5 bytes XD

The Niche

Quote from: Blizzard on February 10, 2011, 12:50:38 pm
Lol, I was already like "98 bytes?! O_O Jesus H. Christ in a chicken basket! O_O"


*Tries to imagine Jesus in a chicken basket*

Ah, right. Miracles.
Level me down, I'm trying to become the anti-blizz!
Quote from: winkio on June 15, 2011, 07:30:23 pm
Ah, excellent.  You liked my amusing sideshow, yes?  I'm just a simple fool, my wit entertains the wise, and my wisdom fools the fools.



I'm like the bible, widely hated and beautifully quotable.

Dropbox is this way, not any other way!

winkio

Just showed my most recent build of this to my university's game development club.  They were impressed :D  But now, there are people that are expecting steady progress on it every week...  :o... *facepalm* why am I so dumb?

Blizzard

Tell them it's like Duke Nukem Forever.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

winkio

February 12, 2011, 04:34:55 pm #34 Last Edit: April 17, 2011, 11:30:40 pm by winkio
Quote from: Blizzard on February 12, 2011, 04:23:58 pm
Tell them it's like Duke Nukem Forever.


...BLIZZ YOU ARE A GENIUS!  The thing is, I actually can make progress pretty easily for a little while working on the basics of the editor, but I know that once I try and integrate the editor with the framework to make a game prototype, all hell is going to break loose.  Hopefully, I can time for that to happen over spring break, and then spend all break fixing it XD

EDIT: small update because I haven't done one in a while:  Tiles of all shapes and sizes are rendering, the game code is started to be built up, starting with the platformer code.