GhostControl not detecting overlap with BetterCharacterControl

Hello,

I am a bit new to JMonkey. My plan is a simple capture the flag game. I got most of the character control and map generation done already but now I’m running into the problem with detecting if a character is touching a flag.

My first idea was to check for location collision but that didn’t work out since I can’t get the physics position of the BetterCharacterControl. So I tried to use the getLocalTranslation() method on the actual spatial but that returned a number which was way off even though the spatial was attached to the rootNode.

After this I came to ghostControl. So I started by setting up PhysicsTickListener in my class and inside the physicsTick() method I check all the overlapping objects of the ghostControl. This for some reason is empty even when my BetterCharacterControl player passes right through the flag.

What is causing the ghostControl not to detect the player?

Code for base/flag:

/*

  • To change this template, choose Tools | Templates
  • and open the template in the editor.
    */
    package org.ctf.control;

import com.jme3.bullet.PhysicsTickListener;
import com.jme3.bullet.collision.PhysicsCollisionObject;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.control.GhostControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Cylinder;
import java.util.Observable;
import java.util.Observer;
import org.ctf.models.Character;
import org.ctf.models.Team;
import org.ctf.util.GlobalStorage;
import org.ctf.util.PhysicsSpace;

/**
*

  • @author thomv
    */
    public class BaseControl implements Observer, PhysicsTickListener {

    private Vector3f location;
    private Team team;
    private Geometry flag;
    private GhostControl control;

    //
    /**

    • Get the value of location
    • @return The value of location
      */
      public Vector3f getLocation() {
      return location;
      }

    /**

    • Get the value of flag
    • @return The value of flag
      */
      public Geometry getFlag() {
      return flag;
      }

    /**

    • Get the value of flag
    • @return The value of flag
      */
      public Team getTeam() {
      return team;
      }

    /**

    • Get the value of control
    • @return The value of control
      */
      public GhostControl getControl(){
      return control;
      }
      //

    /**

    • Creates a physical base on the field

    • @param location The location of the flat base object. Not the pole, not the flag

    • @param team The team the base will be assigned to
      */
      public BaseControl(Vector3f location, Team team){
      this.location = location;
      this.team = team;

      // Generate the physical base
      generateBase();

      // Setup the flag
      resetFlag();
      }

    /**

    • This method will attach the flag of the base to the character
    • @param character The character who touched the flag
      */
      public void stealFlag(Character character){
      System.out.println(team.getName() + “'s flag got stolen.”);
      }

    /**

    • This method will generate the baseplate and pole
      */
      private void generateBase(){
      Geometry base = new Geometry(“Base”, new Cylinder(8, 8, 5, 1, true));
      base.setLocalTranslation(location);
      base.lookAt(new Vector3f(location.x, -1, location.z), new Vector3f(location.x, 1, location.z));

      Material mat = new Material(GlobalStorage.getAssetManager(), “Common/MatDefs/Misc/Unshaded.j3md”);
      mat.setColor(“Color”, ColorRGBA.DarkGray);
      base.setMaterial(mat);

      GlobalStorage.getRootNode().attachChild(base);

      RigidBodyControl baseC = new RigidBodyControl(0);

      baseC.setKinematicSpatial(false);
      base.addControl(baseC);
      PhysicsSpace.add(baseC);

      Geometry pole = new Geometry(“Box”, new Box(0.1F, 3, 0.1F));
      pole.setLocalTranslation(new Vector3f(location.x, location.y + 3, location.z));

      Material mat1 = new Material(GlobalStorage.getAssetManager(), “Common/MatDefs/Misc/Unshaded.j3md”);
      mat1.setColor(“Color”, ColorRGBA.Brown);
      pole.setMaterial(mat1);

      GlobalStorage.getRootNode().attachChild(pole);
      }

    /**

    • This method will reset the flag to the base. Can only be called from inside
      */
      private void resetFlag(){
      this.flag = new Geometry(“Box”, new Box(0.075F, 1, 1));
      this.flag.setLocalTranslation(new Vector3f(location.x, location.y + 4.75F, location.z + 1));

      this.control = new GhostControl(new BoxCollisionShape(new Vector3f(0.075F, 1, 1)));
      this.flag.addControl(this.control);

      Material mat = new Material(GlobalStorage.getAssetManager(), “Common/MatDefs/Misc/Unshaded.j3md”);
      mat.setColor(“Color”, this.team.getColor());
      this.flag.setMaterial(mat);

      GlobalStorage.getRootNode().attachChild(this.flag);

      PhysicsSpace.add(control);
      }

    /**

    • This method is automatically invoked if a character touches a flag
    • @param o The observable object which this method was called from
    • @param arg The additional argument
      */
      @Override
      public void update(Observable o, java.lang.Object arg) {
      Character character = (Character) arg;
      stealFlag(character);
      }
/**
 * 
 * @param space
 * @param tpf 
 */
@Override
public void prePhysicsTick(com.jme3.bullet.PhysicsSpace space, float tpf) { }
/**
 * 
 * @param space
 * @param tpf 
 */
@Override
public void physicsTick(com.jme3.bullet.PhysicsSpace space, float tpf) {
    for (PhysicsCollisionObject obj : this.control.getOverlappingObjects()){
        System.out.println(obj.getUserObject());
    }
}

}

Code for character:

/*

  • To change this template, choose Tools | Templates
  • and open the template in the editor.
    */
    package org.ctf.models;

import com.jme3.bullet.control.BetterCharacterControl;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import org.ctf.util.GlobalStorage;
import org.ctf.util.PhysicsSpace;

/**
*

  • @author thomv
    */
    public abstract class Character extends Entity {
protected Spatial model;
protected Geometry camTarget;
protected BetterCharacterControl control;

protected Team team;
protected int flagsCaptured;
protected int kills;
protected int deaths;

//<editor-fold defaultstate="collapsed" desc="Properties">
/**
 * Get the value of model
 * @return The value of model
 */
public Spatial getModel(){
    return model;
}

/**
 * Get the value of control
 * @return The value of control
 */
public BetterCharacterControl getControl(){
    return control;
}

/**
 * Get the value of team
 * @return The value of team
 */
public Team getTeam(){
    return team;
}

/**
 * Get the value of camTarget
 * @return The value of camTarget
 */
public Geometry getCamTarget(){
    return camTarget;
}

/**
 * Get the value of flagsCaptured
 * @return The value of flagsCaptured
 */
public int getFlagsCaptured(){
    return flagsCaptured;
}

/**
 * Get the value of kills
 * @return The value of kills
 */
public int getKills(){
    return kills;
}

/**
 * Get the value of deaths
 * @return The value of deaths
 */
public int getDeaths(){
    return deaths;
}

/**
 * Set the value of team
 * @param team The new value for team
 */
public void setTeam(Team team){
    this.team = team;
    
    Material mat = new Material(GlobalStorage.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
    mat.setColor("Color", this.team.getColor());
    this.model.setMaterial(mat);
}
//</editor-fold>

public Character(String name, Vector3f location) {
    super(name, location);
    
    this.flagsCaptured = 0;
    this.kills = 0;
    this.deaths = 0;
    
    this.model = GlobalStorage.getAssetManager().loadModel("Models/character/character.j3o");
    this.model.setLocalTranslation(location);
    
    this.control = new BetterCharacterControl(2F, 6F, 10F);
    this.control.setJumpForce(new Vector3f(0, 75, 0));
    this.control.setGravity(new Vector3f(0, 10, 0));
    
    this.model.addControl(this.control);
    
    this.camTarget = new Geometry("Box", new Box(0.1F, 0.1F, 0.1F));
    this.camTarget.setMaterial(new Material(GlobalStorage.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"));
    this.camTarget.setLocalTranslation(0, 3.5F, 0);
    
    Node modelNode = (Node) this.model;
    modelNode.attachChild(this.camTarget);
    
    GlobalStorage.getRootNode().attachChild(this.model);
    
    PhysicsSpace.add(this.control);
}

}

http://javadoc.jmonkeyengine.org/com/jme3/bullet/control/AbstractPhysicsControl.html#getSpatialTranslation--

But that will basically give you the same thing as:

…but the value has to be right or your spatial won’t be drawn in the right place. It is literally “ground truth”.

I don’t know anything about ghost control so I can’t help with that but maybe it’s related to your other issues. Maybe your collision shape is not really where you think it is.

Also, seems like maybe you missed this post:

I figured that part out because in the first case my model would be created halfway the collision box. Therefore I had to go in blender and change the center point to point to the feet of the character.

The only time I ever do something in regard to setting local translation is when I create the character.

Regarding your second post about code blocks. It is my first time posting on this site so I still have to figure it out :grinning:
I literally just used the blockquote and performatted text tools in the editor and it gave me that back.