4
$\begingroup$

Scene:

I have a simple weapon system: weapon which has a ray that collides with game-related objects (i.e. objects that can collide with player); an empty that is always at the end of the ray; and, on a trigger (left click), an object (damage object) is added to the end of the empty, the object changes the health value of an opponent when collision occurs. There is also an opponent, for the simplicity of this question, a cube set to dynamic for physics.

Problem:

I am trying to get the ray to exert a force the way it is facing/going. I'm not quite sure how to create such an idea in the game-engine. How can I have a ray create a force facing the same way the ray is facing/going?

Include/Note

  • Force only affects certain object(s). This/these object(s) are whatever the damage object collides with. In other words, the force will affect no object but those that the damage object collides with. (You can have it collide with the object(s) the ray collides with if you can't do this)
  • Force does not decrease/increase strength over time; force is constant.
  • A property that defines how much force to use.
  • A property that defines how long the force will last.
  • Please try to answer in python.

Any help is appreciated. Thanks!

$\endgroup$
5
$\begingroup$

Due to the dynamic nature of that operation you need a Python controller to apply that impulse/force.

I suggest to use a ray sensor. It provides the object hit, the position where it was hit and the direction you measured. Usage

Place this snippet in a python file force.py

import bge 
import mathutils

PROPERTY_STRENGTH = "strength"
DEFAULT_STRENGTH = 1.0

def applyAtHit():
    if not allSensorsPositive():
        return 
    sensor = getDetectionSensor()
    affectedObject = sensor.hitObject
    hitPosition = sensor.hitPosition

    strength = getOwner().get(PROPERTY_STRENGTH, DEFAULT_STRENGTH)

    direction = mathutils.Vector(sensor.rayDirection).normalized()
    force = direction * strength

    affectedObject.applyImpulse(hitPosition, force)

def getDetectionSensor():
    return bge.logic.getCurrentController().sensors[0]

def getOwner():
    return bge.logic.getCurrentController().owner

def allSensorsPositive():
    for sensor in bge.logic.getCurrentController().sensors:
        if not sensor.positive:
            return False
    return True

Apply following logic to the measuring object:

  • Setup a ray sensor (must be the first one) with a distance that covers the range you want to have, [True Level Triggering] is not needed as you want a single impulse
  • Setup a Python controller in module mode with Module: force.applyAtHit Ensure detected objects are physics objects (dynamic, rigid body, softbody)

enter image description here

How does it work?

When all sensors are positive and any of the sensors triggers the controller the function applyFromHere() will be executed. Each run will apply exactly one force or no force at all. That is the reason for [True Level Triggering] disabled. This prevents subsequent execution unless you "activate" again. Means you need all sensors positive and at least one to trigger.

The ray sensor checks for an hit. The Python controller calculates the

  • the affected object
  • the direction towards the affected object
  • the strength of the force

With that the Python controller applies the individual force to the affected object. Here we use applyImpulse(). This does not just affects the linear motion, it results in change of the torque too.

I hope it helps

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.