Ball doesn't roll straight in Blender Game I'm trying to create a simple golf putt game using the Blender Game Engine as depicted here:



The problem is that the ball doesn't roll straight. If I launch the ball at about 5 degrees left-of-center, I'd expect it to stay on that path until it hits the hole or falls off the board.  Instead it takes a curved "S"-shaped path, apparently affected by the wires that can be seen when rendering the board material as wire.

The problem goes away if I don't cut the hole in the board, apparently because the wires are not present.

Below is a complete script that reproduces the problem. I'm using Blender 2.76 on Mac OS X and running the script at startup using "./blender.app/Contents/MacOS/blender myscript.py".  The problem also occurs for other versions including 2.72, 2.73 and 2.75.

The .blend file resulting from the script below is available here:
https://www.dropbox.com/s/wvwulkjq16au3rw/ball_roll_problem_v276.blend?dl=0
Just press the spacebar after starting the game to launch the ball, and you should see that it follows an "S" path rather than rolling straight.

An updated .blend file with improved mesh is available here:
https://www.dropbox.com/s/vvyb7kkvtk11u3g/ball_roll_problem_v276_remeshed.blend?dl=0
The improved mesh helps the problem, but the ball still doesn't roll straight;  the wires surrounding the hole still cause it to follow an "S" path.   

Is there a way I can get the ball to roll straight? 
Any help would be most appreciated! 

import bpy
import inspect
from math import radians



#(0) Initialize:
bpy.context.window.screen = bpy.data.screens['Game Logic']
scene      = bpy.data.scenes[0]
scene.render.engine = 'BLENDER_GAME'



#(1) Create a board using existing cube:
board          = bpy.data.objects['Cube']
board.name     = 'Board'
board.scale    = 2, 7, 0.1
board.location = 0, 0, -0.1
### cut a hole using boolean difference:
bpy.ops.mesh.primitive_cylinder_add( radius=0.4, location=(0,3,0) )
cylinder           = scene.objects[0]
modifier           = board.modifiers.new('hole_cutter', 'BOOLEAN')
modifier.object    = cylinder
modifier.operation = 'DIFFERENCE'
### apply the modifier:
bpy.ops.object.select_all(action='DESELECT')
bpy.context.scene.objects.active = board
bpy.ops.object.modifier_apply(apply_as='DATA', modifier="hole_cutter")
scene.objects.unlink(cylinder)



#(2) Add a ball:
bpy.ops.mesh.primitive_uv_sphere_add(size=0.1, location=(0, -6, 0.1))
ball       = scene.objects[0]
ball.name  = 'Ball'
### game settings:
ball.game.physics_type = 'RIGID_BODY'
ball.game.use_collision_bounds = True
ball.game.collision_margin = 0
ball.game.collision_bounds_type = 'SPHERE'
ball.game.mass         = 1
ball.game.radius       = 0.1
### game properties:
bpy.ops.object.game_property_new(type='BOOL', name='launched')
ball.game.properties['launched'].value = False
### add controller:
bpy.context.scene.objects.active = ball
bpy.ops.logic.sensor_add(type='ALWAYS')
bpy.ops.logic.controller_add(type='PYTHON')
sensor      = ball.game.sensors[-1]
controller  = ball.game.controllers[-1]
sensor.use_pulse_true_level = True
sensor.link(controller)
### add controller script:
def my_ball_controller():
    import bge
    scene       = bge.logic.getCurrentScene()
    ball        = scene.objects['Ball']
    SPACE_key   = bge.logic.KX_INPUT_ACTIVE == bge.logic.keyboard.events[ bge.events.SPACEKEY ]
    if SPACE_key and not ball['launched']:
        ball.applyForce((-30, 300, 0), 0)
        ball['launched'] = True
bpy.data.texts.new('my_ball_controller')
script          = bpy.data.texts['my_ball_controller']
controller.text = script
lines           = inspect.getsourcelines( my_ball_controller )[0]
for line in lines[1:]:
    script.write( line[1:] )



#(3) Set camera location:
camera  = bpy.data.objects['Camera']
camera.location       = (0, -12, 3)
camera.rotation_euler = (radians(70), 0, 0)
### set camera view:
for screen in bpy.data.screens[3:5]:
    for area in screen.areas:
        if area.type == 'VIEW_3D':
            for space in area.spaces:
                space.region_3d.view_perspective = 'CAMERA'
As you have  noted the mesh is the issue , switch to wireframe view and launch the BGE to see how it get triangulated ( combined with some rounding errors ) it will cause the deviation of the ball.

To avoid that you have to add either a Subsurf modifier ( in simple mode ) or a Remesh modifier ( in sharp mode ) and apply it before adding the Boolean modifier this will limit the bad triangulation inside a small area ( all the mesh are triangulated when passed to the BGE)

#(1) Create a board using existing cube:
....
### add and apply subsurf 
modifier           = board.modifiers.new('subsurf', 'SUBSURF')
modifier.levels    = 2
modifier.subdivision_type = 'SIMPLE'
bpy.ops.object.select_all(action='DESELECT')
bpy.context.scene.objects.active = board
bpy.ops.object.modifier_apply(apply_as='DATA', modifier="subsurf")

### cut a hole using boolean difference:
....