2015-03-08 01:14:51 (edited by camlorn 2015-03-08 01:15:51)

Okay.
First, the Pyglet speech thing.  Turn typing echo off or put the screen reader in sleep mode.  Count on keys being spoken.  Whether or not the keys will get spoken depends so ridiculously on the screen reader it's not even funny.  None of us can take over Pyglet, and I feel like you're just trying to find reasons to complain at me about it.  If you really don't want Pyglet, ignore me and don't have it.
Second, you are using what most people I can think of would consider bad code structure.  Among other things, it intrinsically links the receiving of events to the tick, which only holds true for naive implementations like Pygame.  It makes it such that you need to use if statements all down your tick method, making it hard to actually conceptualize it in one small piece.  If you ever want control remapping or anything like that and you're using this approach, you're probably going to have to pollute the whole app with it.  All keyboard code has to run every tick, rather than just happening when a key happens.  You are probably building a dictionary of every possible event and whether it happened, which is expensive.  If you aren't, then I need to start checking to see what's in the dict or not.  If you are re-using the dict, I give you 3 months before someone does the obvious thing of throwing extra stuff in it and expecting it to be there later.  Port to a different framework and the code to manage that dict becomes complicated: what if I press and release a key before the tick interval completes?  And finally, you can't respond to the keyboard immediately, which will make everything laggy unless you're using a pretty high tick rate.
But more generally, classes are an accepted way to do something and the pattern therein is used by most libraries.  You almost never see something like this, and trying to force BGT into Python isn't going to actually help anyone much.  If you really want to offer this functionality, build it on top of what I'm suggesting.  Aim to minimize if statements whenever possible, as if statements are complexity.  Encourage the use of well-named flags because if needs_jump is way better than if key=="space" for readability in 6 months.  Use subclassing because it's an accepted convention and because encouraging the use of subclassing is usually a good thing for game design.
if you really want to make this convenient, make an @on_key("space") decorator and let people use that.
To go back to one thing that deserves elaboration, the key response shouldn't happen on the tick.  Doing this in a menu will make it feel laggy unless the tick rate is high, and most people don't want or need to run that high.  Part of the Pyglet event loop lets you avoid running hot while still giving you the events as they happen, but you can't really duplicate that in Pygame to my knowledge.  To that end, your main loop probably needs to end up running as fast as it can with very, very small sleeps and some conditions to see if enough time has passed to tick stuff.  You can cover up the fact that the game is ticking slowly by playing sounds immediately when keys are pressed, and then carrying out the actions in a couple hundredths of a second at the next tick.  You are trying to bring a BGT concept that is bad out of BGT, and I strongly encourage you to not do that if at all possible.  Yes, its simple to do what you're doing.  but it's almost as simple to do what I'm doing, your code self-documents, and you keep flexibilities in the API and the logic that you don't have right now.

My Blog
Twitter: @camlorn38 (Try Chicken Nugget)

Thumbs up

2015-03-09 01:48:59

So essentially there is a separate thread that waits for events to happen and when events happen, they run through the events scheduled in the stack?
That is why you can't have a dict, because a dict is dependent on everything going on in frames where as the goal is to have everything happening instantly?
I think the only way you could do this in pygame would be to have 2 threads, one for the timer, logic and whatnot and another thread running pygame.event.wait() that will do the stack code event checks. (key_up, key_down, mouse_move... but not tick, tick for each screen happens in the main loop.


I got AvBin working,
There is a folder with all the dlls
that you place in the same folder as the script and it runs perfectly.

Thumbs up

2015-03-09 03:04:12

no. You don't want threads here.  What you do want is to pass on events as soon as you see them, at least if that's possible.  Even if it's not, you don't want to expose it this way. It might be later, and it's best not to introduce lag.
Right now, what you would do is have an if statement that moves stuff if a key is down.  A smarter way is to give everything a velocity.  In the on_key_down function, look for the arrow keys and set the velocity on the player.  On the on_key_up function, clear it.  Then, everything is happily handled by the movement code.  By looking at the movement code, I understand everything about movement. By looking at the keyboard functions, I understand everything about the keyboard.  But these concepts are separate: I can work on one without even seeing the other.
But more generally, by combining stuff like this in tick, you're treating the keys and the mouse as special.  The keys and the mouse aren't special.  The keys and the mouse are indicating to my game that something should happen, but the actual code that makes things happen can and should be as separate as possible.  The code that does things can then be shared between the player (keyboard and mouse), the AI code (everything else), and the network (maybe, it's a little more complicated than that, but the general point stands).  My current project takes this to an extreme you don't need to go to; it's possible to make all display and input completely separate from all logic.
This is called the model view controller pattern, and the more you look like the model view controller pattern the better.  In the model view controller pattern, there are three things.  The model is the world and all the code to do things to the model.  The view is the code dealing with screen, sound and text to speech.  The controller is the keyboard, mouse or network code.  The more these are separate the happier you're going to be later when your game gets upwards of, say, 2000 lines.  How they communicates varies.  I like publish subscribe frameworks like blinker and the Queue module, and my current project pretends there's a network even though there's not.
But more seriously, if you've not done a game of Shades of Doom complexity in Python, please do so now.  You're trying to set precedent potentially for a very long time, and I've never seen a game from you.  This is part of the reason I'd not do this project myself: I have nothing completed and released, though I do have a number of failed and successful but I don't care projects.  Making game engines for everyone is not something I feel comfortable doing, not because I can't.  You're solving problems for everyone, not just for yourself, and you will never, ever, ever be able to back out and say "I was wrong".  I'd usually just shrug and go "yes, this works" and it does, for a reasonably simple and possibly even an intermediate game.  But you're not making a game.

My Blog
Twitter: @camlorn38 (Try Chicken Nugget)

Thumbs up

2015-03-09 09:39:18

Does the model queue events onto both the view's queue and the controller's queue?
Then both the controller and view run through the items in their prospective queues either every loop (for view) or when an action is pressed (for the controller view)?


BTW, what textbooks do you know of, or websites do you know of that describe different user interface architectures like model view control?
Also, the different ideas behind the screen handling?
I've just been making stuff up at this point which is why the design is pretty bad. They were the first thing that popped into my head... They were also what the example games I've seen use, but all those were from pygame, explaining graphics.
I actually never have used BGT, I've just been approaching everything from what I knew of the game loop in pygame.
I've asked questions in different places, but I got back responses that either made no sense or were worse than what I was using. So I guess It was because my whole design process was flawed that we weren't understanding one another. Thank you for noticing and explaining why my approach was flawed.
I think the reason why I have never put out a game is because every time I think I'm ready, I will start, then find out that it is 100 times easier to do what I've been doing. The problem is that it would be easier then to rewrite the whole game from the ground up and I wasn't married to the game idea. Putting out a library like this was a way to place into concrete the ideas I already knew were the way to do things in the best way. I wanted people to then do what you are doing in saying either "no!!! we do it this way and this is why" or "yes, this is awesome! can it do this now"...
It is possible to write shades of doom in just functions and if statements, but it would just be incredibly huge and unwieldy. (I think it would be like writing shades of doom in C). When I first learned if statements, I wrote a blackjack game in just functions and if statements. It worked, but because there were no loops, I'm pretty sure it wins the record for the worst python code imaginable.
Do if statements fall under the category in OO programming as a necessary evil? People say that they are bad, but up to this point I didn't understand why. Now I see that if statements make the code more and more unreusable.

Thumbs up

2015-03-09 14:43:11

Well, it doesn't have to be queues.  And in all honesty, allowing the game to play sounds directly isn't horrible.  I'm going to go into my current project a bit.  This is advanced, and you don't have to do it this way.  You probably shouldn't go this far unless your goal is an online game.  But this is basically as pure as the MVC pattern gets, and it's way purer than 90% of games do.
So, some motivation: my long-term goal is online World of Warcraft for the blind.  To that end, I want to see if things work before I go do that, and I need to test Libaudioverse at the same time. To that end, my current project is Shades of Doom, with a twist.
The twist?  There's a client and a server in the same process, and they talk via a queue.  I'm not using threads, I'm just ticking both of them.  Specifically, they use 4 major messages to mirror object state and a bunch of smaller ones to tell the client what kind of important event happened.  The client then does stuff off the important events.  The server has no idea what kind of thing the client might do, just that it needs to post things like collision because they're "important".
The server also does not know about the keyboard.  The part of the server which talks to the client accepts and processes messages that are requests to set properties or do actions from the client.  When this part of the server receives such a message, it makes whatever necessary changes must be made to the simulation before the next tick, i.e. setting the player's velocity or spawning a projectile.  The regular general-purpose simulation code then picks it up without any further special handling.
But more realistically for you, playing sounds directly isn't horrible.  It's not a bad idea to have some separate code that knows how to attach looping sounds to objects, but if the projectile is responsible for playing its sound when it hits the enemy or whatever, that's not so bad.  But, unlike sounds, there's basically zero reason to make keyboard and mouse handling be in the same place as everything else.  Checking the is_jumping flag is much more self-documenting, and there's nothing saying that you can't make whatever method calls you need to make on the model of your game world in a key_down function.  The other ironic bit of this is that often you only care about key_up events; this complicates things further when it's the case.  And then someone asks you for control remapping or you want to use the touch screen.
As for if statements, I'm not saying they're evil.  The evil thing here is code complexity.  If you have to have complex code, you want to break it up into simple pieces as much as possible.  Since the keyboard handling doesn't need to live with the game logic, separate them.  You want to look at as little logic as possible when making a change.  I'm not going off OO programming here, I'm going off general stuff.  There's a couple heuristics that new programmers are often quoted, but I don't personally find them too helpful; you'll just break them because they're almost impossible to follow in real projects.  But if you want a concrete thing in your code to consider evil, how about these: higher indentation levels are more evil than lower indentation levels and longer functions taking many parameters are more evil than shorter functions taking fewer parameters.
Beware, though, for you can take this too far the other way.  You're not even close to that point at the moment, but if you separate logic I need to see in order to make even small changes, you have the same sorts of problems for different reasons.
As for patterns?  i don't have anything specific.  MVC is a thing you can arrive at on your own, but my knowledge of the name comes from Angular.js and the Apple Objective-c docs.  There are many good books on program design in general and quite a few good ones on game design, but I don't have any I'd personally recommend.  It's a good idea, though; I got to do it by making all the mistakes myself.  The one thing I do have that's useful is this page which has a good list of topics about most game development things.

My Blog
Twitter: @camlorn38 (Try Chicken Nugget)

Thumbs up

2015-03-09 16:39:32

Oh thanks, that website will be super helpful.
So you have the game code in the model in tick that says something like:
if flags.jump:
player.jump()
flags.jump = False


In the control or client you have:
key_dict = {"run_forward": "up", "run_right": "right", "jump": "space"}

def key_down(key, mods):
if key == key_dict['jump']:
  flags.jump = True


Then in player.jump it looks like:
def jump(self):
self.y += 2
self.move_forward(x=1)
schedule_event(self.move_forward, 0.5, x=1)
schedule_event(self.come_down, 1.0)
self.sound['jump'].play()



Or is this interaction more like:
game code in the model tick:
for event in event_queue:
event.run()
if not event.keep:event_queue.remove(event)


Then in the controller you have:
key_dict = {"run_forward": "up", "run_right": "right", "jump": "space"}

def key_down(key, mods):
if key == key_dict['jump']:
  event_queue.append_event(player.jump)


Then in jump you have an instance of an event class like:
class Jump(event):
def run(self):
  player.y += 2
  player.move_forward(x=1)
  schedule_event(player.move_forward, 0.5, x=1)
  schedule_event(player.come_down, 1.0)
  player.sound['jump'].play()


Then in player you have in __init__:
class player(object):
def __init__(self, ...):
  self.jump = Jump()


Or is it something different altogether? This is a new mindset for me, so I would like to make sure I have it clear.

Thumbs up

2015-03-09 17:03:36

The first one you have is probably more applicable to side-scrollers.  The second one is probably more applicable to an RTS.  They're both right.
A few things can make it simpler:
Everything that can move has a velocity attribute.  Every tick, whatever is in charge of movement adds the velocity to the position, unconditionally.  You may then write code that plays movement sounds, but this code need not necessarily be in the movement function that's adding velocities.  If something's not moving, just put it's velocity at 0.
Nothing is wrong with calling the jump function directly from the keyboard handlers.  This is an action which happens on a key, so there's no specific need to duplicate the check.  Flags are for continuous states.  Also, nothing stops you from making a version of the class that has key_down and key_up functions that look up what to call from a dict, thus allowing you to do something like:

self.key_up_handlers={"space": self.jump}

in your __init__ function.  You can handle key maps with the getattr function if you want them to be externally loadable.
You don't want to use the event scheduling unless you wrote it.  It seems like a very good idea, but just decrementing counters is probably better.  It makes aborting actions easier, and the game will not pause properly if you just schedule them and throw them away like that.  One thing you can do is put it in the screen base class; the scheduling of an event records the number of ticks until the event needs to happen and the base class calls it when it's ready.  This lets you pause while jumping, for example.
Unless the player moves forward a precise amount, jumping shouldn't handle movement.  The player is either in the air or not in the air.  The arrows still handle movement in that case.  If the jumps are precise, just play the jump sound and teleport the player to the new position instantly; no one will be able to tell the difference.
I'd strongly suggest not writing an engine right now.  I'd strongly suggest writing and releasing a game.  Engines have very strong guarantees on compatibility.  Once you do this and get people, you're locked into whatever you come up with.  This is the same reason we haven't had a bunch of Libaudioverse previews from me: once I encourage people to use it, I'm stuck whether it's good or not, basically for the rest of forever.  If you think you will make mistakes or wish you'd done something differently, it is best by far to do so in something disposable or one-off.

My Blog
Twitter: @camlorn38 (Try Chicken Nugget)

Thumbs up

2015-03-09 21:21:22

OK, that is a little more of what I normally would do, have something like:
def on_key_down(key, mods):
if key == player.key_list['jump']:
   player.jump()


That way we cut out half of the code for the model tick function.


I have been reading pyglet's API and code but I am a little lost on why they did 3 things:
1. Why in the world did they go implicit on the pygame.window.Window class? It's really disconcerting. The code looks like:
import pyglet
window = pyglet.window.Window(caption="My test screen")
pyglet.app.run()

2. Their event EventDispatcher seems to just be one screen and it is not really built for different screens. Especially if you would like lots of moving on and off screens. It is very implicit. I need to do more testing but either I found a bug or it is not very clean.
For example, if I add on 2 of the same screen in a row, then remove the last screen, no matter what I do, it will remove all of the same screens in one removal.
3. Is there an advantage to making all the characters variables? because what they say to do is:
@window.event
def on_key_press(key, mods):
if key == window.key.SPACE:
  spk("Hello world")



that window.key.SPACE is really strange to me. I kind of like having my keys as strings. I'm considering making a little function to make the keys strings, but if there is a good reason for the variable, I can keep it.
What I was thinking is if someone wished to remap key.SPACE to a g or something, it would be really easy to say that key.SPACE = the number for g.
Is there a good reason for this?

Thumbs up

2015-03-09 22:49:35

I don't know what you're doing with events, but either there's a major bug that I haven't found out yet, the programming guide is lying, or you're doing something wrong.  Have you read this section of it?
As for the variables, well, yes.  There sort of is.  The key codes are integers.  You can go back and forth if you must, or just deal with it.  If you do go back and forth, you will be dealing with some very deep Python magic involving dir, getattr, and other stuff.
Also:

from pyglet.window import key

will let you just do key.SPACE, etc.  Personally I'd just deal with it, but if you *really* need strings I can give you a ten-line function off the top of my head that will give you a lookup table.
And as for your first question, I'm trying to decipher specifically what you mean by implicit.  But window is an event handler and you're only going to want one.  So create one and use push_handlers with your screen objects and pop_handlers to get rid of them.  You can subclass it, yes, but that only works if you don't need multiple levels of events (or possibly even then, but I wouldn't want to reason about the semantics).  Windows are not screens.  Maybe think of them as portals: they're where input enters your system before your code even has a chance to touch it  and, if you're using graphics, where output leaves it after your code is done.

My Blog
Twitter: @camlorn38 (Try Chicken Nugget)

Thumbs up

2015-03-09 23:11:02

I am going to start making a game now, so perhaps it will become more clear.
What I mean by implicit is that in the code:
import pyglet
window = pyglet.window.Window()
pyglet.app.run()
has no code telling me that the window is attached to app. For that matter, I have no idea where app came from. I could understand with one or the other, but both is a little baffling.

Thumbs up

2015-03-10 01:08:34

Yeah. Pyglet does "lazy" imports.  I consider this stupid.  You can import pyglet.window and you can import pyglet.app but, honestly, it's pretty clear from the context that something is going on and you should look it up.  Still, meh. Really bad practice.
As for pyglet.app.run, that's standard.  It's the event loop.  Same as wx.app.MainLoop.  Anything that needs to use the event loop is attached, i.e. everything in the whole library. You will see this in at least Wx and twisted, and if you did your engine on top of Pygame you'd probably have something that's the same in all but name.
Do not forget:

import pyglet
pyglet.options['shadow_window']=False

which must run before anything else is imported from Pyglet if those of us using Intel graphics drivers will be able to reliably run your stuff.  Don't ask, if you want details, I should have linked the thread earlier.  And before you run for Pygame, the broken thing in Pygame is modifier keys which can get stuck in odd states, particularly if the user happens to be holding one when the program starts; this plagues SoundRTS to this day.

My Blog
Twitter: @camlorn38 (Try Chicken Nugget)

Thumbs up

2015-03-10 10:08:51

pygame has a lot of problems with the mod keys.
Actually what is happening is that there are 2 values for mod keys. I have the full list, but you can also get the bug when you alt tab and do something in another window and come back.
I have actually found quite a few bugs in pygame, not least of which is that it takes a second or so before it opens up a window...
Thanks for the Shadow window, I'll put that in my scripts.

Thumbs up

2015-03-10 15:40:19

Someone needs to figure those out.  I've seen a couple similar things with Pyglet, but nothing on the order of Pygame.  Yet.

My Blog
Twitter: @camlorn38 (Try Chicken Nugget)

Thumbs up

2015-03-31 00:03:44 (edited by frastlin 2015-03-31 17:39:07)

So I have been dealing with pyglet now for a while and getting used to it's sound syntax and whatnot, but while running up against it's lack of a simple panning feature I ran into panda 3d. Have you used panda3d
before? It is an incredible library with pre-built support for all the libraries I have heard you talk about. It also has its own system for running tasks where you can create a list of tasks to run and they act like a recording where you can speed them up, jump forward and whatnot. It also has some huge huge huge development support, including Carnegie Mellon university and Disney...
It also has support for running it through a web browser and connecting it with a web client.
They give a guide for running WXPython in it and running panda 3d in Twisted.
The git page is under constant development and I think the community is quite large. It also has a C++ version as well, so I think you can use both when developing.
I think the only thing it doesn't have just quite yet is a port to IOS and Android, but there are a lot of people talking about porting them over, it just hasn't been done yet...

Thumbs up