• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.

Redleaf

Members
  • Content count

    266
  • Joined

  • Last visited

Community Reputation

219 Neutral

About Redleaf

  • Rank
    Member

Personal Information

  1. Have you taken a look at Pyrex yet? I'm sharing this in case you're doing some exploring to find alternative ways to create Python extensions. I've used SWIG too, and Pyrex seems a lot nicer to work with.
  2. Good question. I forget the exact path I took while learning to use twisted. I would begin by reading some of the core developer how-to guides. I don't recommend reading them all, or even from top to bottom, as a lot of that information probably won't be important to you. I think I started with Perspective Broker, which will probably be the kind of network programming you're looking for.
  3. Straying from your technical question slightly, if you really want to see python's power when it comes to network programming, maybe you should give twisted-matrix a try. Your file-sharing app might be much easier to write this way.
  4. Well, the problem is that __del__ will only be called when the toto object is being cleaned up. Therefore, a del self.Gen statement will also only be executed then. However, as long as there are references to the toto object, it will not be cleaned up. self.Gen has one of those references, and so it creates a reference cycle with the toto object.
  5. Because of the way a proxy works, when you call a method through one, it actually will be the object that it is a proxy to. These two will be equivalent: self.Gen = proxy(self).Generator() self.Gen = self.Generator() So this way will not work. However, there is a way to do what you want. self.Gen = toto.Generator(proxy(self)) By calling the method through the class and passing the proxy explicitly, the self parameter is now actually the proxy. In case you ever decide you need to be more general about the class, you can do something like this: self.Gen = self.__class__.Generator(proxy(self)) This might be an even better solution. Hope this helps.
  6. Sorry, there is a slight problem with the example I gave. You have to make sure you iterate your generator at least once in order to get the proxy installed. If the generator is never iterated, it will continue to hold the original self and prevent cleanup. Having it install during the object creation is relatively simple to do though: from weakref import proxy class toto: def __init__(self): print "Init" self.Gen = self.Generator() self.Gen.next() # install the proxy def __del__(self): print "Del" def Generator(self): self = proxy(self) # now there won't be zombification yield None # end of proxy installation for i in range (100): print i yield i def Step(self): self.Gen.next() Now your objects can be cleaned up even if they never call Step().
  7. Good question, and I'm glad you asked. This is actually a reasonably simple problem to solve with weakrefs. You can read more about the module "weakref" in the python docs. Lots of good information. Anyway, a simple proxy will prevent your generator from storing a reference to the instance, and it can then be cleaned up as you expect. from weakref import proxy class toto: def __init__(self): print "Init" self.Gen = self.Generator() def __del__(self): print "Del" def Generator(self): self = proxy(self) # now there won't be zombification # note that you only need self if you make use of it here for i in range (100): print i yield i def Step(self): self.Gen.next() Of course, as in your example, if you don't actually make use of the "self" object, so you can simply del self, or not even have the generator as a method.
  8. What he meant was that if you had an original list with multiple references: data = [1,2,3,4,5] data2 = data Then this line would cause changes in data to also be seen by data2: data[:] = list(line.split() for line in data)
  9. All of that makes sense. Thank you both for the clarification.
  10. Departing slightly from the main topic, how would using a generator expression compare? data = list(line.split() for line in data) or data[:] = list(line.split() for line in data) In some profiling tests where I've compared them to list comprehensions, it seems the generator expressions are a little faster. The documentation also claims that generator expressions are more memory efficient. Is there any reason to use list comprehensions instead? (Sorry for the slight question hijack, but this is something I've been curious about.)
  11. Generally that might be true about C++ support, but what about a library like Twisted Matrix? Surely if you were familiar with it you wouldn't say that this library wasn't worth anything to game programming, and it's not easily usable with C++ as far as I can tell. As far as simplicity goes, that's always a good thing. But isn't the page just a list of links by category anyway? I'm not sure I see how additions of this type would dramatically increase the complexity. Maybe the core audience needs to be more open-minded, and have a chance of being exposed to more alternatives? A few months ago I would have considered myself part of that core audience, and I consider it a crime that I wasn't seriously exposed to such alternatives earlier. You could be doing others a big favor.
  12. How about some kind of information showing what languages each library has bindings for? Or better yet, listing all libraries that support a particular language under one section. For instance: Python: -pygame -pyopengl -pyode -twistedmatrix etc. That's something I would be interested to see. The existing categories don't have to be broken down necessarily, but it would also be nice to have libraries related by language found in the same place. At the moment, it seems the list is mainly geared towards C++. Maybe an organizational change would entice more people to list libraries for use with other languages?
  13. If you're brave enough, you can even venture into the source and see if you can find/fix the problem and submit a patch proposal. That's one of the great things about open source software... you can look at the source :-P.
  14. I noticed this problem after one of the more recent versions of SDL came out, and it just seems that it never was fixed for 1.2.8. I think it was fine in 1.2.6. Anyway, it's not a very serious issue, and most games would run in fullscreen anyway, right? I imagine nobody got around to the fix. Kind of a funny observation: If you maximize the window (title bar will now be higher than your screen) and then minimize, and then restore, it will end up back to normal too. This also only seems to happen in windows, as the linux build of my SDL apps resize normally.
  15. [size="5"]Premise This article will introduce some new concepts that will allow us eventually to model higher-level languages with simple bytecode instructions. The variable data associated with scripts will become part of a stack, which will enhance the higher level behavior we can achieve with a handful of opcodes, and allow us to evaluate complex mathematical expressions with relative ease. With these new facilities added, it will also be possible for our scripts to have controlled program flow, including patterns for if-else and loops, as well as script-based functions. [size="5"]The Reason for a Stack A stack is a natural representation for many types of systems involving states and procedural calculation. One such use as mentioned is in evaluating expressions that involve more than a single operation, since such expressions can be broken into parts and handled step by step. Consider a simple arithmetic expression: [bquote][font="Courier New"][color="#000080"]x + y * p[/color][/font][/bquote] Knowing simple rules for the ordering of operations, we can create a procedure for evaluating such an expression: [bquote][font="Courier New"][color="#000080"]multiply y by p add the result with x[/color][/font][/bquote] Place this expression in the context of variable assignment, and you will begin to see how it relates to programming: [bquote][font="Courier New"][color="#000080"]i = x + y * p multiply y by p add the result with x assign the final result as the value of i[/color][/font][/bquote] Notice that the procedure for evaluating such an expression mentions something that is only implicitly present in the expression itself. The procedure uses a term "result" which is understood to mean the result from the previous partial evaluation. It's almost an automatic assumption that we set aside the results of these sub-evaluations for use in further evaluations. What a stack will do for us is allow us to make this natural assumption. Being a LIFO (last in first out) data structure, we can push values onto it, pop them off to perform an operation, push the result back on, and so on until the parent evaluation is completed. By following a consistent set of evaluation rules, we can ensure that the stack will manage these "results" without us having to keep track of them. [size="5"]Implementing a Stack One of the first things that come to mind when thinking about stack implementations is that simple containers that could be used are already implemented as part of the standard library. They certainly are. However there will be certain features we need that they do not provide on their own. We will start with a simple stack that uses a vector for its implementation: template class ScopeStack { public: ScopeStack() {} ScopeStack(size_t reserveSize) { _stack.reserve(reserveSize); } // todo: scope interface // element interface void Push(const T& element) { _stack.push_back(element); } void Pop() { assert(!_stack.empty()); _stack.pop_back(); } // accessors const T& Top() const { assert(!_stack.empty()); return _stack.back(); } T& Top() { assert(!_stack.empty()); return _stack.back(); } const T& Get(size_t index) const { assert((index)Data()[0]; else ++_instr; _stack.Pop(); break; case op_jump_if_false: if (_stack.Top() == 0) _instr = _instrPtr + _instr->Data()[0]; else ++_instr; _stack.Pop(); break; These two instructions will behave as stated, moving to a new position after examining the value at the top of the stack, and popping it off before they are done. [size="5"]Higher-Level Constructs An explanation of how such low-level jump instructions relate to higher-level control structures is due. I will now illustrate a few examples of C-style constructs and their equivalent jump instruction patterns in our bytecode. Note that although our parser doesn't support commenting, I will be using them in the example scripts shown. The If-Else Clause: C: if (condition) { // do something } else { // do something else } Script: // evaluate condition jump_if_false A // A corresponds to an appropriate value to reach the position marked A: // do something jump B A: // do something else B: The While Loop: C: while (condition) { // do something } Script: A: // evaluate condition jump_if_false B // do something jump A B: The Do-While Loop: C: do { // do something } while (condition); Script: A: // do something // evaluate condition jump_if_true A As you can imagine, dealing with the low-level jump instructions can be tedious, particularly when figuring out the appropriate index to jump to. A more robust development tool would certainly include a way to label positions in the code, and have jump instructions reference the labels, as I've shown in the examples above. But the idea here was to show that in the appropriate patterns our jump instructions could represent higher-level constructs. [size="5"]Conditional Expressions In order to drive our new conditional jumps, we need to have instructions that yield conditional results. Instructions performing value or logical comparison make the most sense in this case, and most will function much like the instructions implementing binary operations in the earlier section. Unary: op_not: performs a logical negation of the top of the stack Binary: Each of these compares the top two values on the stack, popping the top and returning an appropriate true/false to the new top. op_and: performs logical conjunction op_or: performs logical disjunction op_equal op_not_equal op_greater op_greater_equal op_less op_less_equal This condition: [bquote][font="Courier New"][color="#000080"](x > 1) && (x 1) { result *= counter; --counter; } // output return result; } We can begin deconstruction by analyzing the number of variables we will need to track, and in this case it is two (counter and result). The parameter input can be simulated as a constant supplied at the very beginning of our script. We will use index 0 as the counter, and index 1 as the result: // initialize push_const Input // the actual value here is mutable assign 0 push_const 1 assign 1 Handling the final output is also an easy section to deconstruct: // output push_var 1 output end The tricky part now comes in while flattening out the iterative loop. However, all we need to do is use the pattern described earlier for simulating a while loop: A: // evaluate condition jump_if_false B // do something jump A B: The condition to be evaluated is simply a comparison between counter and the value 1: // counter > 1 push_var 0 push_const 1 greater And the action we are taking within the loop (do something) is multiplying result by counter, assigning the product to result, and then decrementing counter: // result *= counter; push_var 1 push_var 0 multiply assign 1 // --counter; push_var 0 push_const 1 subtract assign 0 Now we put all of these pieces together, to get this: push_const Input // the actual value here is mutable assign 0 push_const 1 assign 1 A: push_var 0 push_const 1 greater jump_if_false B push_var 1 push_var 0 multiply assign 1 push_var 0 push_const 1 subtract assign 0 jump A B: push_var 1 output end The result is 20 instructions (not counting the labels of course). To finalize the process, we replace A and B by the proper offsets in our list. A corresponds to the 5th instruction, and B corresponds to the 18th (remember not to count A: as an instruction). Using 0 to N-1 index convention, that gives the 5th instruction an offset of 4, and the 18th an offset of 17. A script that outputs the factorial of 4: push_const 4 assign 0 push_const 1 assign 1 push_var 0 push_const 1 greater jump_if_false 17 push_var 1 push_var 0 multiply assign 1 push_var 0 push_const 1 subtract assign 0 jump 4 push_var 1 output end [size="5"]Interesting Results If you play around with the script's initial input value, you'll come to realize something... It only outputs the correct value for an input of 5 or less! What happened? The reason for this is our stack contains elements of type char, which implies a range of -128 to 127. The factorial of 5 is 120, just barely making the cut. So what if we want to find the factorial of 7? We only have to make a small change. Behold the power of templates: class Execution { . . . private: ScopeStack _stack; // initially of type ScopeStack . . . }; The factorial of 7 now comes out to be 5040, as it should be. [size="5"]Conclusion In my opinion, these have most interesting concepts developed in our low-level implementation so far. Although it is obviously tedious work, scripts can now be written to express many of the simple higher-level concepts we have always taken for granted. I leave the expression of some other high-level constructs (such as functions) as exercises for the reader until next time. The tools for expressing simple functions are here. Check out the downloadable source for certain small changes in the test program we built last time in order to allow for our new instructions. One change was made to the parser to allow for underscores to be scanned as part of an opcode name. Other changes were made, but due to their trivial nature, they don't change the way the program behaves, and aren't really worth mentioning. Please give me a piece of your mind in the forum discussion, or via my website