Advice needed

Hi, y’all!
Following lots of questioning, reading, testing, failing and other lots of activities ending in “ing”, I managed to get this far (see file and laugh maniacally at my puny ability to make a crap creation). Well, if you know it, I decided to make something along the lines of “Kosmonaut” or “Sky Roads”. I’ll call it “Komandant”.

komandant.blend (562 KB)

Why I chose them as examples to follow:

Simple controls: - throttle, braking, jumping, left and right. <- Implemented, but not completely happy with it.
Simple imaging: - Sky ahead, a road only forward <- Simple implementation, I need some pointers, though.
Simple menus: - I have a stupid-ish menu. Simple for now, obviously because I only have one option. <- I understand the dynamics behind scene changing, so that’s covered.

On to the doubts:
1)
I’d like to improve the controls, by making impossible changing direction in mid-jump, while still responding to the last direction given. Example: player moves right and jumps to the right. Disallow sudden left motions while airborne. Current implementation kindly given by SolarLune makes it so that if I negate sliding in the air, the cube only goes straight up.

Is there a better way to provide a backdrop other than “materializing” a plane or is that the safest, better way?

For all intents and purposes, is scene.replace() good for dealing with scene changing, or am I better off using scene.addScene()/scene.end() combo?

Could someone explain this dumb guy here why does it appear the same texture 4 times on the plane/button? In GLSL it shows ok, but multitexture it behaves wrongly…
Thanks. May the gods of froth smile upon thyselves and prevent baldness upon thy head.

You just about answered your own question. All you need to do is add a check before you process your key presses and ignore the keypresses if your player is not on your track. Something like:


if groundCheck.positive:
  # handle key presses

Is there a better way to provide a backdrop other than “materializing” a plane or is that the safest, better way?

I would recommend using a “sky box” for the background. They are pretty simple to setup and if you just try to use a simple plane for your background then you can run into problems if you ever move your camera or even change the resolution.

For all intents and purposes, is scene.replace() good for dealing with scene changing, or am I better off using scene.addScene()/scene.end() combo?

That I’m not sure about.

Could someone explain this dumb guy here why does it appear the same texture 4 times on the plane/button? In GLSL it shows ok, but multitexture it behaves wrongly…
Thanks. May the gods of froth smile upon thyselves and prevent baldness upon thy head.

[/QUOTE]

I’m not sure. Your texture was not packed with the .blend file so I could not see it regardless.

For backgrounds, beckground scenes are the way to go if you don’t want them to move.

As for 1, like Kastoria said, just enforce friction if you’re on the ground only, and only take keypresses if you’re on the ground. If you jump, then the speed should stay the same.

For 2, if you want a sky / background, you should generally use a background scene, since it won’t move.

For 3, scene.replace should be fine. You could go with adding and removing as well; the difference is minimal. Either way, it will take one game frame to replace the scene with another one.

For 4, I believe you have to unwrap your mesh to use texture coordinates. In Multitexture mode, it probably will automatically use the UV values, but in GLSL mode, you have to change the texture’s mapping coordinates from Generated to UV (in the Texture panel, next to the Material panel). As a side-note, blend files don’t automatically contain resources like fonts, textures, or sounds. You have to pack them in via the File > External Data menu, or the empty little ‘tray’ next to the resource’s path (a page gets put into it when the resource is packed).

Ok, cool! This is close, but just this much to get there!komandant.blend (655 KB)

Following your advice, I got a background loading with a nice skybox (obviously, placeholder crappy art, but it works for my immediate needs), loading and unloading it when needed. I unfortunately had to do it with the logic editor, because I couldn’t find a way to load it through script. No harm done, though. It works, fine by me. Niceties will have to come later.

With the mapping, I had to do that UV unwrapping and got it working ok. I kinda dislike UV mapping, but it’s an inevitability, so I’d better get used to it.

Unfortunately, I am yet to solve my control requirements. I used that advice even before starting, and the cube goes straight up, I even referenced that in my first message. I posted the amended example with textures packed so you guys can see it better.

Thanks for the help, guys. You make learning much more fun! Blender is a harsh master…

EDIT:
With a background scene, does a textured plane work as or should I aim to a skybox? I don’t need to have a skybox because I’ll only be looking to the front…

Also, testing a more ambitious image, I noticed a lag between my skybox and main track, any advice to prevent this?

I added friction and maximum speed in to the object’s X-axis movement, as well as only allowing friction to work on the object when the groundcheck sensor is positive.

You can load and unload scenes with logic.addScene(scenename, overlay) (the first argument being the name of the scene to add, and the second being whether to have the scene be overlay or not), and remove them with scene.end().

You can grab scenes to end with logic.getSceneList(), which returns a Python list consisting of scenes currently being displayed and updated (not all of the scenes present in the blend file). You can search for one with a specific name by using a list expression (I think is what it’s called):



scelist = logic.getSceneList()

bgscene = [s for s in scelist if 'Background' in s.name][0]


A list expression creates a list consisting of all arguments in another list (s for s in scelist). It also will add them in if the if-expression evaluates as true (if ‘Background’ in s.name). The final part, [0], gets the first argument in that ‘outputted list’, and assigns it to the bgscene property. This entire expression looks for any scenes currently in-game that have ‘Background’ in their names. You could also just use “if s.name == 'Background”, for example, to check for a completely equal name.

A textured plane should be fine. By lag, I’m not 100% sure what you mean. If you mean the skybox loads in after the main track scene, it’s because it takes a game frame to load in another scene.

komandant(2).blend (631 KB)

Thank, SolarLune! You are the man!

x -= math.copysign(1, x) * friction if abs(x) >= abs(friction) else x

I’m having a bit of trouble wrapping my head around this line, especially understanding what copysign actually does. Language barrier, maybe. Does math.copysign(1, x) make “1” positive or negative, copying the sign of “x”?

bgscene = [s for s in scenelist if ‘background’ in s.name][0]

returns a list with scenes with background in the name and

bgscene.end()
ends them all, correct?

EDIT:
<- Dumb person is dumb…

Oddly, I tried to use this too:

bge.logic.addScene(‘background_1’, 0)
but got errors that it was already added… :confused::confused::confused:

Anyway, thanks for mentoring me! I have a bit of trouble with the code, but I’ll have to make it through.

You are correct. There’s no Python sign() function that just returns the sign (1, 0, or -1) for a number, but, as the Python help docs mention, copysign() returns the first argument with the sign of the second argument. So, copysign(1, argument) basically gives the sign of the argument (1, 0 (I assume), or -1).

In the example above, bgscene gets a list of scenes with ‘background’ in the name, but the [0] at the end gets the first element (scene) in that list. From there, bgscene.end() would just end that scene. If you wanted to end them all, you could do:



[s.end() for s in logic.getSceneList()] # Probably would crash on trying to end the last, only remaining scene

# Or, alternatively,

for s in logic.getSceneList(): # Again, would probably crash the BGE on trying to end the last remaining scene
     s.end()


EDIT: And that error is just saying that the scene is already added if you try to add it more than once (i.e. adding the scene every game frame). The error shouldn’t have any effect on the game, other than making it slow down slightly from printing the error to the console every frame.

No problem. Hope you find the BGE fun and easy to use.

for the error change this

if mouse_click.status==2: scene.replace(“track_1”)

to

if mouse_click.status==1: scene.replace(“track_1”)


status -&gt; mean

0            you not press nothing
1            key press the first time(one step)
2            key still pressed (can be many step)
3 key released (one step)

so meanly one normal click can return this status:

0
0
0
0
1
2
2
3
0
0

@MarcoIT:
Good stuff, thanks!

I have this code attached to an empty, in a menu scene with several planes, being used as buttons:
Three sensors connected, ‘MouseOver’ being a mouse over any with Pulse mode on.


import bge

cont = bge.logic.getCurrentController()
scene = bge.logic.getCurrentScene()
mainChar = cont.owner

mouse = bge.logic.mouse

mouse_click_l = cont.sensors['MouseL']
mouse_click_r = cont.sensors['MouseR']
mouseover = cont.sensors['MouseOver']

button=mouseover.hitObject
print(button)

if mouse_click_l.status==1 and button=='button_1':
    print("Scene 1")
    #bge.logic.addScene('background_1', 0)
    #scene.replace("track_1")
    
if mouse_click_r.status==1:
    dirlist=(dir(mouse_click_r))
    for printdir in dirlist:
        print(printdir)

This line works: print(button)
It shows the button name perfectly, so the button is correctly identified when mouse is over it.

Thing is, this block doesn’t:

if mouse_click_l.status==1 and button=='button_1':
    print("Scene 1")
    #bge.logic.addScene('background_1', 0)
    #scene.replace("track_1")

The print(“Scene 1”) command never triggers, but my investigations take me to this, that my brain marks as an impossibility:


button=mouseover.hitObject
print(button)

if mouseover.hitObject=='button_1':
    print("Scene 1")

The “if” block never fires…

What is going on? I’m starting to think I can’t do anything right in this contraption…

A) Better use the status constants for input rather then the cryptic integer values. It will be much more readable.
B) KX_GameObject are no strings. So it makes no sense to compare a KX_GameObject with a string. It can’t become True.

Thanks, Monster! After reading your topic, it became clearer. I was relying in the console’s raw output and I was misled.

Ok, one question out of the way, one still remaining.

Changing this:


button=mouseover.hitObject
print(button)
 if mouseover.hitObject=='button_1':
     print("Scene 1")

To this:



button=mouseover.hitObject
print(button)
if button.name=='button_1':
     print("Scene 1")

Makes it work, but errors pop up when not hovering over any object about "AtributeError: ‘NoneType’ object has no attribute ‘name’.

I went around it and made the name check after each mouse click and works wonderfully! I think it’s even better this way, so the game isn’t always checking the object’s names.

Thanks!

Your solution is basically correct. When the mouse over sensor isn’t firing, then its hitObject variable is set to None. You can check mouseover.positive first to ensure that it did fire over an object, and then check mouseover.hitObject (or button, as above). Python is, if I recall correctly, a short-circuit language, so if the current test in an if-statement fails, then the rest won’t be evaluated. For example, "if mouseover.positive and mouseover.hitObject.name == “Button” works because if the mouse over sensor isn’t positive, then its hitObject variable won’t be checked to see if it’s name is equal to “Button”.

mouseover.positive is perfect! Eliminates every possible error message. Silly of me for not remembering that one.

About the reusage of objects among scenes. I’m thinking of eliminating redundancy by using the same objects over and over. I created a “menu” scene, a “full” track, with a course and ship and 7 more scenes to contain a track each.

I’d like to eliminate the need to create a camera, and a ship in each, so what’s the better path to follow?
Put all objects in a background scene (i think it’s rather trivial to copy objects among active scenes, though I may be exaggerating my skills) and copy them to the active scene or what? Putting the objects in a hidden layer doesn’t seem the ideal path to take in this case.

I believe code follows the objects, as I made a group with the ship and a sensor and they work as intended…

I’m not advanced user like the teachers have been helping you (you are very lucky, they are the best here around…)

What I have usually watched in examples (like Inventory cases) is what you commented it, place all the objects in another layer in a scene all together if those objects would be appear in different scenes (for example, Level 1, Level 2, etc…) I would put in always active scene, like in the ‘HUD’, then you are able to access them easier.

Yeah, I understand what you say, but loading all objects at once, even if inactive, would possibly put a strain on the system?

Well, you can use add the player and other necessary bits to a group and add it in to each game scene (as you seem to have already tried out), or link objects between scenes with Control+L. If you put the camera in a group and add it in, you won’t be able to access it (i.e. look through it) in Blender, though you can set the active scene camera to that particular camera with Python easily.

Please tell meh, I have beautiful text, serving as a timer, the text appears ok (white) if I run the scene, whether in the embedded player or in the standalone player, but if I use it as an overlay, the text appears black. Black, I tell you! Pitch black! Black as the blackest pits of hell where black evil things make you black out. And I cannot fathom why such a predicament happens…

Pray help me.
(Two Worlds kind of plea, if thyselves are wondering)

EDIT:
Myself has resolved the issue, though much to my dislike, I do not find the solution encountered, how can i pose it… Ideal, mayhaps?

From such code:


if button.name=='button_1'
    bge.logic.addScene('background', 0)
   bge.logic.addScene('hud', 1)
   scene.replace('track_1')

Converting it to:


if button.name=='button_1'
    bge.logic.addScene('background', 0)
   bge.logic.addScene('hud', 1)
   bge.logic.addScene('track_1', 0)
   scene.end()

Made it work.

Hm, that’s odd. Maybe you’re running a different texture mode than when you’re looking at the scene directly? The shading mode (GLSL, Multi-texture, Single-texture) can be changed on a per-scene basis, but it won’t change between scenes. So, be sure that you’re looking at your scenes in the shading mode that you need. Also, text color isn’t dictated by material, but rather by the object color picker in the Object tab (why, I don’t know; it just is).