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'