What is wrong with this code?

import bpy

from mathutils import noise

#how many cubes you want to add on each axis
count = 100

for i in range (0,count):
for cube_instance in range(0,count):
x = 1
y = 1 + i
position = [x, y, 0]
H = 2
lacunarity = .5
octaves = 4
z = mathutils.noise.fractal(position, H, lacunarity, octaves, noise_basis=noise.types.STDPERLIN)
#z = 0
bpy.ops.mesh.primitive_cube_add(location=(x * cube_instance + 1,y,z))

I’m getting the error message “Python script fail, look in console for now”, then the line starting with z = is highlighted.

Any help would be appreciated.

most likely because you imported specifically ‘noise’ not ‘mathutils’,
so you can use ‘noise.fractal’ instead of ‘mathutils.noise.fractal’.

And ‘bpy.ops.mesh.primitive_cube_add’ is not a game engine function.

So what should I change the code to? The second statement you made isn’t correct because that part of the code works.

When posting code please use [noparse]

[/noparse] tags. Otherwise it is nearly unreadable.

Then run it without Blender and you will see.

bpy is the Blender API. You are talking with Blender not with the BGE.

Blender is not present when running the blender player -> the import will fail.
Requesting changes to Blender (bpy.ops.mesh.primitive_cube_add) will modify Blender and has no effect with the BGE.

Imagine following: You are sitting in your car (car = your current game instance) now you call the car factory (Blender) to add a cube on top of your car. What will happen?

The car factory will add this cube to the blue prints of the car (=new version of the car). You will not get a cube on the car you are currently driving.
When you buy a new car (= restart the BGE) you get a car with the cube.

That is the difference on import bge and import bpy.

Btw. mathutils is an utility library (toolset). It is delivered within the blender player and therefore available in the car (your game).

So import bge?

Yes. Never import bpy when using the game engine. only use bge.

To add a new cube you do a copy of an existing but inactive object. Inactive objects reside in an hidden layer.

You add the copy either via AddObject Actuator or via KX_Scene.addObject() call.

Perlin Noise Terrain.blend (422 KB)

Could you check the .blend file? I tried changing it to import bge and it didn’t work.

Perlin Noise Terrain.blend (386 KB)

Updated but still not functioning.

I looked at the blend and the reason nothing works is because nothing is set to work. you must first add logic to something. like an always sensor connected to a python controller.

Done that, I’ve added an empty and added a Keyboard sensor (press W) linking in to a Python Controller. Still nothing. What should I connect the Python controller to? BTW I’ve specified ‘module’ and then typed in the right python code.

Here’s the .blend Perlin Noise Terrain.blend (421 KB)

You used module import in the controller brick instead of script import.


Blender Game Engine Started
Python module name formatting error in object 'Cube.001', controller 'Python':
        expected 'SomeModule.Func', got 'Perlin Terrain'

Also,

This has so many mistakes in it…

z = mathutils.noise.fractal(position, H, lacunarity, octaves, noise_basis=noise.types.STDPERLIN)
KX_Scene.addObject(Cube(location(x * cube_instance + 1,y,z)))

Would you settle for mathematical Sinusoidal map as it a lot easier for beginners?

also, made it so that it re-generates the terrain around the ‘player’ when you press w and move…

Attachments

Sinusoidal Terrain.blend (476 KB)

What are the mistakes?

Much appreciated. I’m just looking to learn as much as I can however I can so I’m quite happy to use this although I would also like to learn about Perlin and how to produce Perlin terrain. If you don’t do things that are difficult then you’ll never get better, right?

I will help you with perlin noise after school.

Cheers man. I honestly appreciate all the help. I wouldn’t be asking all these questions if there were any good tutorials out there. Unfortunately BGE tutorials are few and far between.

mathutils.noise.fractal implies that you are using noise function that is resides in the mathutils module.
That is fine :smiley:
But later “noise_basis=noise.types.STDPERLIN” you expect the object noise to be defined?
python does not know if you mean mathutils.noise or someotherlibrary.noise…

KX_SCENE was said that was where you should have used addObject on, true.
But, KX_SCENE is the class, not the instance that the game runs. for that you would need


# scene here is a KX_SCENE instance, as the name implies it is also the current scene
scene = bge.logic.getCurrentScene()

Now also, here again, where was KX_SCENE defined?
you did not import it, you did not define it, so it could not have worked, the game simply does not know what/where a “KX_SCENE” is…

Moving on, addObject is the correct function but it does take two arguments.
None of which are “Cube” objects or such…
The correct information can be found here:
https://docs.blender.org/api/2.78b/bge.types.KX_Scene.html#bge.types.KX_Scene.addObject
So basically you can reference the object what you want as a game object or simply as the objects name “Cube”.

Finally, “Cube(location(x * cube_instance + 1,y,z))”
The objects Cube and location are not defined anywhere, again, and what is more are not how bge/python works.
We do not have a class Cube, but we have access to the game objects in the hidden layer.
We do not have location object, but we have “.worldPosition” on game objects and Vector class in mathutils for the location data.

Bonus round, cube_instance, is a bad variable name as it gives you wrong idea for its purpose.

So now all those changes can now be seen in the code that i provided

  • Everything that is used is defined at some point.
  • Location is handled nicely
  • The scene to spawn things in is defined as an instance.
  • spawning a game object named cube is executed according to the API.

import bge
from math import sin




def main():
    cont = bge.logic.getCurrentController()
    own = cont.owner
    current_x, current_y = own.worldPosition.xy
    
    scene = bge.logic.getCurrentScene()


    radius = 10
    for dx in range(-radius, radius):
        for dy in range(-radius, radius):
            x, y = round(current_x + dx), round(current_y + dy)
            z = round(sin(x / 8) * sin(y / 8) * 7)
            
            cube = scene.addObject('Cube', own)
            cube.worldPosition = x, y, z
        

I enjoy the readiness to learn :smiley:
The problem was that you tried to run before you could walk.
Always try to break the challenge into smaller pieces solve the smaller problems first.

Like:

  • How do I run a script in bge
  • How do I import what i need
  • How do I spawn a simple cube
  • How do I use some fancy magic function