Package advanced.physics.scenes

Source Code of advanced.physics.scenes.AirHockeyScene$GameFieldHalfDragListener

package advanced.physics.scenes;

import java.awt.event.KeyEvent;

import org.jbox2d.collision.AABB;
import org.jbox2d.collision.shapes.CircleDef;
import org.jbox2d.collision.shapes.PolygonDef;
import org.jbox2d.collision.shapes.Shape;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.BodyDef;
import org.jbox2d.dynamics.ContactListener;
import org.jbox2d.dynamics.World;
import org.jbox2d.dynamics.contacts.ContactPoint;
import org.jbox2d.dynamics.contacts.ContactResult;
import org.jbox2d.dynamics.joints.Joint;
import org.jbox2d.dynamics.joints.JointType;
import org.jbox2d.dynamics.joints.MouseJoint;
import org.mt4j.MTApplication;
import org.mt4j.components.MTComponent;
import org.mt4j.components.visibleComponents.font.FontManager;
import org.mt4j.components.visibleComponents.font.IFont;
import org.mt4j.components.visibleComponents.shapes.MTEllipse;
import org.mt4j.components.visibleComponents.shapes.MTLine;
import org.mt4j.components.visibleComponents.shapes.MTRectangle;
import org.mt4j.components.visibleComponents.widgets.MTTextArea;
import org.mt4j.input.inputProcessors.IGestureEventListener;
import org.mt4j.input.inputProcessors.MTGestureEvent;
import org.mt4j.input.inputProcessors.componentProcessors.dragProcessor.DragEvent;
import org.mt4j.input.inputProcessors.componentProcessors.dragProcessor.DragProcessor;
import org.mt4j.input.inputProcessors.globalProcessors.CursorTracer;
import org.mt4j.sceneManagement.AbstractScene;
import org.mt4j.util.MTColor;
import org.mt4j.util.camera.MTCamera;
import org.mt4j.util.math.ToolsMath;
import org.mt4j.util.math.Vector3D;

import processing.core.PApplet;
import processing.core.PImage;
import advanced.physics.physicsShapes.IPhysicsComponent;
import advanced.physics.physicsShapes.PhysicsCircle;
import advanced.physics.physicsShapes.PhysicsRectangle;
import advanced.physics.util.PhysicsHelper;
import advanced.physics.util.UpdatePhysicsAction;

public class AirHockeyScene extends AbstractScene {
  private float timeStep = 1.0f / 60.0f;
  private int constraintIterations = 10;
 
  /** THE CANVAS SCALE **/
  private float scale = 20;
  private MTApplication app;
  private World world;
 
  private MTComponent physicsContainer;
  private MTTextArea t1;
  private MTTextArea t2;
 
  private int scorePlayer1;
  private int scorePlayer2;
  private HockeyBall ball;
  /*
  private Minim minim;
  private AudioSnippet wallHit;
  private AudioSample paddleBallClash;
  private AudioSnippet goalHit;
  private AudioSnippet paddleHit;
  */
  private Paddle redCircle;
  private Paddle blueCircle;
 
  private boolean enableSound = true;
 
 
  //TODO sometimes goal not recognized when shot at fast
  //TODO after goal reset puck and make 3 second countdown -> dont use physics until countdown up!
  //TODO get graphics, sounds, effects
 
//  private String imagesPath = System.getProperty("user.dir") + File.separator + "examples" + File.separator +"advanced"+ File.separator +  "physics"  + File.separator + "data" +  File.separator  + "images" +  File.separator;
  private String imagesPath =  "advanced" + MTApplication.separator +  "physics"  + MTApplication.separator + "data" +  MTApplication.separator  + "images" +  MTApplication.separator;
 
 
  public AirHockeyScene(MTApplication mtApplication, String name) {
    super(mtApplication, name);
    this.app = mtApplication;
//    this.setClearColor(new MTColor(120,150,150));
//    this.setClearColor(new MTColor(190, 190, 170, 255));
    this.setClearColor(new MTColor(0, 0, 0, 255));
//    this.setClearColor(new MTColor(40, 40, 40, 255));
    this.registerGlobalInputProcessor(new CursorTracer(app, this));
   
    this.scorePlayer1 = 0;
    this.scorePlayer2 = 0;
   
    float worldOffset = 10; //Make Physics world slightly bigger than screen borders
    //Physics world dimensions
    AABB worldAABB = new AABB(new Vec2(-worldOffset, -worldOffset), new Vec2((app.width)/scale + worldOffset, (app.height)/scale + worldOffset));
    Vec2 gravity = new Vec2(0, 0);
    boolean sleep = true;
    //Create the pyhsics world
    this.world = new World(worldAABB, gravity, sleep);
   
    //Update the positions of the components according the the physics simulation each frame
    this.registerPreDrawAction(new UpdatePhysicsAction(world, timeStep, constraintIterations, scale));
   
    physicsContainer = new MTComponent(app);
    //Scale the physics container. Physics calculations work best when the dimensions are small (about 0.1 - 10 units)
    //So we make the display of the container bigger and add in turn make our physics object smaller
    physicsContainer.scale(scale, scale, 1, Vector3D.ZERO_VECTOR);
    this.getCanvas().addChild(physicsContainer);
   
    //Create borders around the screen
    this.createScreenBorders(physicsContainer);
   
    //Create gamefield marks
    MTLine line = new MTLine(mtApplication, mtApplication.width/2f/scale, 0, mtApplication.width/2f/scale, mtApplication.height/scale);
    line.setPickable(false);
//    line.setStrokeColor(new MTColor(0,0,0));
    line.setStrokeColor(new MTColor(150,150,150));
    line.setStrokeWeight(0.5f);
    physicsContainer.addChild(line);
   
    MTEllipse centerCircle = new MTEllipse(mtApplication, new Vector3D(mtApplication.width/2f/scale, mtApplication.height/2f/scale), 80/scale, 80/scale);
    centerCircle.setPickable(false);
    centerCircle.setNoFill(true);
//    centerCircle.setStrokeColor(new MTColor(0,0,0));
    centerCircle.setStrokeColor(new MTColor(150,150,150));
    centerCircle.setStrokeWeight(0.5f);
    physicsContainer.addChild(centerCircle);
   
    MTEllipse centerCircleInner = new MTEllipse(mtApplication, new Vector3D(mtApplication.width/2f/scale, mtApplication.height/2f/scale), 10/scale, 10/scale);
    centerCircleInner.setPickable(false);
    centerCircleInner.setFillColor(new MTColor(160,160,160));
//    centerCircleInner.setStrokeColor(new MTColor(150,150,150));
//    centerCircleInner.setStrokeColor(new MTColor(0,0,0));
    centerCircleInner.setStrokeColor(new MTColor(150,150,150));
    centerCircleInner.setStrokeWeight(0.5f);
    physicsContainer.addChild(centerCircleInner);
   
    //Create the paddles
    PImage paddleTex = mtApplication.loadImage(imagesPath + "paddle.png");
    redCircle = new Paddle(app, new Vector3D(mtApplication.width - 60, mtApplication.height/2f), 50, world, 1.0f, 0.3f, 0.4f, scale);
    redCircle.setTexture(paddleTex);
    redCircle.setFillColor(new MTColor(255,50,50));
    redCircle.setNoStroke(true);
    redCircle.setName("red");
    redCircle.setPickable(false);
    physicsContainer.addChild(redCircle);
   
    blueCircle = new Paddle(app, new Vector3D(80, mtApplication.height/2f), 50, world, 1.0f, 0.3f, 0.4f, scale);
    blueCircle.setTexture(paddleTex);
    blueCircle.setFillColor(new MTColor(50,50,255));
    blueCircle.setNoStroke(true);
    blueCircle.setName("blue");
    blueCircle.setPickable(false);
    physicsContainer.addChild(blueCircle);
   
    //Create the ball
    ball = new HockeyBall(app, new Vector3D(mtApplication.width/2f, mtApplication.height/2f), 38, world, 0.5f, 0.005f, 0.70f, scale);
//    MTColor ballCol = new MTColor(0,255,0);
//    ball.setFillColor(ballCol);
    PImage ballTex = mtApplication.loadImage(imagesPath + "puk.png");
    ball.setTexture(ballTex);
//    ball.setFillColor(new MTColor(160,160,160,255));
    ball.setFillColor(new MTColor(255,255,255,255));
    ball.setNoStroke(true);
    ball.setName("ball");
    physicsContainer.addChild(ball);
    ball.getBody().applyImpulse(new Vec2(ToolsMath.getRandom(-8f, 8),ToolsMath.getRandom(-8, 8)), ball.getBody().getWorldCenter());
   
    //Create the GOALS
    HockeyGoal goal1 = new HockeyGoal(new Vector3D(0, mtApplication.height/2f), 50, mtApplication.height/4f, mtApplication, world, 0.0f, 0.1f, 0.0f, scale);
    goal1.setName("goal1");
    goal1.setFillColor(new MTColor(0,0,255));
    goal1.setStrokeColor(new MTColor(0,0,255));
    physicsContainer.addChild(goal1);
   
    HockeyGoal goal2 = new HockeyGoal(new Vector3D(mtApplication.width, mtApplication.height/2f), 50, mtApplication.height/4f, mtApplication, world, 0.0f, 0.1f, 0.0f, scale);
    goal2.setName("goal2");
    goal2.setFillColor(new MTColor(255,0,0));
    goal2.setStrokeColor(new MTColor(255,0,0));
    physicsContainer.addChild(goal2);
   
    //Make two components for both game field sides to drag the puks upon
    MTRectangle leftSide = new MTRectangle(
        PhysicsHelper.scaleDown(0, scale), PhysicsHelper.scaleDown(0, scale),
        PhysicsHelper.scaleDown(app.width/2f, scale), PhysicsHelper.scaleDown(app.height, scale)
        , app);
    leftSide.setName("left side");
    leftSide.setNoFill(true); //Make it invisible -> only used for dragging
    leftSide.setNoStroke(true);
    leftSide.unregisterAllInputProcessors();
    leftSide.removeAllGestureEventListeners(DragProcessor.class);
    leftSide.registerInputProcessor(new DragProcessor(app));
    leftSide.addGestureListener(DragProcessor.class, new GameFieldHalfDragListener(blueCircle));
    physicsContainer.addChild(0, leftSide);
    MTRectangle rightSide = new MTRectangle(
        PhysicsHelper.scaleDown(app.width/2f, scale), PhysicsHelper.scaleDown(0, scale),
        PhysicsHelper.scaleDown(app.width, scale), PhysicsHelper.scaleDown(app.height, scale)
        , app);
    rightSide.setName("right Side");
    rightSide.setNoFill(true); //Make it invisible -> only used for dragging
    rightSide.setNoStroke(true);
    rightSide.unregisterAllInputProcessors();
    rightSide.removeAllGestureEventListeners(DragProcessor.class);
    rightSide.registerInputProcessor(new DragProcessor(app));
    rightSide.addGestureListener(DragProcessor.class, new GameFieldHalfDragListener(redCircle));
    physicsContainer.addChild(0, rightSide);
   
    //Display Score UI
    MTComponent uiLayer = new MTComponent(mtApplication, new MTCamera(mtApplication));
    uiLayer.setDepthBufferDisabled(true);
    getCanvas().addChild(uiLayer);
    IFont font = FontManager.getInstance().createFont(mtApplication, "arial", 50, new MTColor(255,255,255), new MTColor(0,0,0));
   
    t1 = new MTTextArea(mtApplication, font);
    t1.setPickable(false);
    t1.setNoFill(true);
    t1.setNoStroke(true);
    t1.setPositionGlobal(new Vector3D(5,30,0));
    uiLayer.addChild(t1);
   
    t2 = new MTTextArea(mtApplication, font);
    t2.setPickable(false);
    t2.setNoFill(true);
    t2.setNoStroke(true);
    t2.setPositionGlobal(new Vector3D(mtApplication.width - 65 , 30,0));
    uiLayer.addChild(t2);
    this.updateScores();
   
    //Set up check for collisions between objects
    this.addWorldContactListener(world);

    /*
    //Sound
    if (enableSound){
      minim = new Minim(mtApplication);
      wallHit = minim.loadSnippet(MT4jSettings.getInstance().getDataFolderPath() + "sound" + File.separator + "paddleBallHit.wav");
//      paddleBallClash = minim.loadSample(MT4jSettings.getInstance().getDataFolderPath() + "sound" + File.separator + "paddleBallHit.wav", 2048);
//      goalHit = minim.loadSnippet(MT4jSettings.getInstance().getDataFolderPath() + "sound" + File.separator + "goal.wav");
//      goalHit.play();
      paddleHit = minim.loadSnippet(MT4jSettings.getInstance().getDataFolderPath() + "sound" + File.separator + "wallHit.wav");
    }
    */
  }
 
 
 
  private class GameFieldHalfDragListener implements IGestureEventListener{
    private MTComponent comp;
   
    public GameFieldHalfDragListener(MTComponent dragComp){
      this.comp = dragComp;
      if (comp.getUserData("box2d") == null){
        throw new RuntimeException("GameFieldHalfDragListener has to be given a physics object!");
      }
    }
   
    public boolean processGestureEvent(MTGestureEvent ge) {
      DragEvent de = (DragEvent)ge;
      try{
        Body body = (Body)comp.getUserData("box2d");
        MouseJoint mouseJoint;
        Vector3D to = new Vector3D(de.getTo());
        //Un-scale position from mt4j to box2d
        PhysicsHelper.scaleDown(to, scale);
        switch (de.getId()) {
        case DragEvent.GESTURE_DETECTED:
          comp.sendToFront();
          body.wakeUp();
          body.setXForm(new Vec2(to.x,  to.y), body.getAngle());
          mouseJoint = PhysicsHelper.createDragJoint(world, body, to.x, to.y);
          comp.setUserData(comp.getID(), mouseJoint);
          break;
        case DragEvent.GESTURE_UPDATED:
          mouseJoint = (MouseJoint) comp.getUserData(comp.getID());
          if (mouseJoint != null){
            boolean onCorrectGameSide = ((MTComponent)de.getTargetComponent()).containsPointGlobal(de.getTo());
            //System.out.println(((MTComponent)de.getTargetComponent()).getName()  + " Contains  " + to + " -> " + contains);
            if (onCorrectGameSide){
              mouseJoint.setTarget(new Vec2(to.x, to.y))
            }
          }
          break;
        case DragEvent.GESTURE_ENDED:
          mouseJoint = (MouseJoint) comp.getUserData(comp.getID());
          if (mouseJoint != null){
            comp.setUserData(comp.getID(), null);
            //Only destroy the joint if it isnt already (go through joint list and check)
            for (Joint joint = world.getJointList(); joint != null; joint = joint.getNext()) {
              JointType type = joint.getType();
              switch (type) {
              case MOUSE_JOINT:
                MouseJoint mj = (MouseJoint)joint;
                if (body.equals(mj.getBody1()) || body.equals(mj.getBody2())){
                  if (mj.equals(mouseJoint)) {
                    world.destroyJoint(mj);
                  }
                }
                break;
              default:
                break;
              }
            }
          }
          mouseJoint = null;
          break;
        default:
          break;
        }
      }catch (Exception e) {
        System.err.println(e.getMessage());
      }
      return false;
    }
  }
 
 
  private class Paddle extends PhysicsCircle{
    public Paddle(PApplet applet, Vector3D centerPoint, float radius,
        World world, float density, float friction, float restitution, float worldScale) {
      super(applet, centerPoint, radius, world, density, friction, restitution, worldScale);
    }
    @Override
    protected void bodyDefB4CreationCallback(BodyDef def) {
      super.bodyDefB4CreationCallback(def);
      def.fixedRotation = true;
      def.linearDamping = 0.5f;
    }
  }
 
  private class HockeyBall extends PhysicsCircle{
    public HockeyBall(PApplet applet, Vector3D centerPoint, float radius,
        World world, float density, float friction, float restitution, float worldScale) {
      super(applet, centerPoint, radius, world, density, friction, restitution, worldScale);
    }
   
    @Override
    protected void circleDefB4CreationCallback(CircleDef def) {
      super.circleDefB4CreationCallback(def);
      def.radius = def.radius -5/scale;
    }
    @Override
    protected void bodyDefB4CreationCallback(BodyDef def) {
      super.bodyDefB4CreationCallback(def);
//      def.linearDamping = 0.15f;
      def.linearDamping = 0.25f;
      def.isBullet = true;
      def.angularDamping = 0.9f;
     
//      def.fixedRotation = true;
    }
  }
 
 
  private class HockeyGoal extends PhysicsRectangle {
    public HockeyGoal(Vector3D centerPosition, float width, float height,
        PApplet applet, World world, float density, float friction,float restitution, float scale) {
      super(centerPosition, width, height, applet, world, density, friction,restitution, scale);
    }
   
    @Override
    protected void bodyDefB4CreationCallback(BodyDef def) {
      def.isBullet = true;
      super.bodyDefB4CreationCallback(def);
    }

    @Override
    protected void polyDefB4CreationCallback(PolygonDef def) {
      super.polyDefB4CreationCallback(def);
      def.isSensor = true; //THIS AS SENSOR!
    }
  }
 
 
 
 
  private void addWorldContactListener(World world){
    world.setContactListener(new ContactListener() {
      public void result(ContactResult point) {
//        System.out.println("Result contact");
      }
      //@Override
      public void remove(ContactPoint point) {
//        System.out.println("remove contact");
      }
      //@Override
      public void persist(ContactPoint point) {
//        System.out.println("persist contact");
      }
      //@Override
      public void add(ContactPoint point) {
//        /*
        Shape shape1 = point.shape1;
        Shape shape2 = point.shape2;
        final Body body1 = shape1.getBody();
        final Body body2 = shape2.getBody();
        Object userData1 = body1.getUserData();
        Object userData2 = body2.getUserData();
       
        if (userData1 instanceof IPhysicsComponent  && userData2 instanceof IPhysicsComponent) { //Check for ball/star collision
          IPhysicsComponent physObj1 = (IPhysicsComponent) userData1;
          IPhysicsComponent physObj2 = (IPhysicsComponent) userData2;
//          System.out.println("Collided: " + mt4jObj1 + " with " + mt4jObj2);
          if (physObj1 instanceof MTComponent && physObj2 instanceof MTComponent) {
            MTComponent comp1 = (MTComponent) physObj1;
            MTComponent comp2 = (MTComponent) physObj2;

            //Check if one of the components is the BALL
            MTComponent ball = isHit("ball", comp1, comp2);
            final MTComponent theBall = ball;
           
            //Check if one of the components is the GOAL
            MTComponent goal1 = isHit("goal1", comp1, comp2);
            MTComponent goal2 = isHit("goal2", comp1, comp2);
           
            //Check if a puck was involved
            MTComponent bluePuck = isHit("blue", comp1, comp2);
            MTComponent redPuck = isHit("red", comp1, comp2);
           
            //Check if a border was hit
            MTComponent border = null;
            if (comp1.getName() != null && comp1.getName().startsWith("border")){
              border = comp1;
            }else if (comp2.getName() != null && comp2.getName().startsWith("border")){
              border = comp2;
            }
           
            if (ball != null){
              //CHECK IF BALL HIT A PADDLE
              if (enableSound && (bluePuck != null || redPuck != null)){
//                System.out.println("PUCK HIT BALL!");
                /*
                triggerSound(paddleHit);
                */
              }
             
             
              //Check if BALL HIT A GOAL
              if (goal1 != null || goal2 != null){
                //BALL HIT A GOAL
                if (goal1 != null){
                  System.out.println("GOAL FOR PLAYER 2!");
                  scorePlayer2++;
                }else if (goal2 != null){
                  System.out.println("GOAL FOR PLAYER 1!");
                  scorePlayer1++;
                }
               
                //Update scores
                updateScores();
                //Play goal sound
//                triggerSound(goalHit);
               
                if (scorePlayer1 >= 15 || scorePlayer2 >= 15){
                  reset();
                }else{
               
                //Reset ball
                if (theBall.getUserData("resetted") == null){ //To make sure that we call destroy only once
                  theBall.setUserData("resetted", true);
                  app.invokeLater(new Runnable() {
                    public void run() {
                      IPhysicsComponent a = (IPhysicsComponent)theBall;
                      a.getBody().setXForm(new Vec2(getMTApplication().width/2f/scale, getMTApplication().height/2f/scale), a.getBody().getAngle());
//                      a.getBody().setLinearVelocity(new Vec2(0,0));
                      a.getBody().setLinearVelocity(new Vec2(ToolsMath.getRandom(-8, 8),ToolsMath.getRandom(-8, 8)));
                      a.getBody().setAngularVelocity(0);
                      theBall.setUserData("resetted", null);
                    }
                  });
                }
                }
               
              }
             
              //If ball hit border Play sound
              if (enableSound && border != null){
                /*
                triggerSound(wallHit);
                */
              }
            }
          }
        }else{ //if at lest one if the colliding bodies' userdata is not a physics shape
         
        }
//        */
      }
    });
  }
 
  /*
  private void triggerSound(AudioSnippet snippet){
    if (!snippet.isPlaying()){
      snippet.pause();
      snippet.rewind();
      snippet.play();
    }
  }
  */
 
  private MTComponent isHit(String componentName, MTComponent comp1, MTComponent comp2){
    MTComponent hitComp = null;
    if (comp1.getName() != null && comp1.getName().equalsIgnoreCase(componentName)){
      hitComp = comp1;
    }else if (comp2.getName() != null && comp2.getName().equalsIgnoreCase(componentName)){
      hitComp = comp2;
    }
    return hitComp;
  }
 
  private void updateScores(){
    t1.setText(Integer.toString(scorePlayer1));
    t2.setText(Integer.toString(scorePlayer2));
  }
 
  private void reset(){
    if (ball.getUserData("resetted") == null){ //To make sure that we call destroy only once
      ball.setUserData("resetted", true);
      app.invokeLater(new Runnable() {
        public void run() {
          IPhysicsComponent a = (IPhysicsComponent)ball;
          a.getBody().setXForm(new Vec2(getMTApplication().width/2f/scale, getMTApplication().height/2f/scale), a.getBody().getAngle());
//          a.getBody().setLinearVelocity(new Vec2(0,0));
          a.getBody().setLinearVelocity(new Vec2(ToolsMath.getRandom(-8, 8),ToolsMath.getRandom(-8, 8)));
          a.getBody().setAngularVelocity(0);
          ball.setUserData("resetted", null);
        }
      });
    }
    this.scorePlayer1 = 0;
    this.scorePlayer2 = 0;
    this.updateScores();
  }
 
 
  private void createScreenBorders(MTComponent parent){
    //Left border
    float borderWidth = 50f;
    float borderHeight = app.height;
    Vector3D pos = new Vector3D(-(borderWidth/2f) , app.height/2f);
    PhysicsRectangle borderLeft = new PhysicsRectangle(pos, borderWidth, borderHeight, app, world, 0,0,0, scale);
    borderLeft.setName("borderLeft");
    parent.addChild(borderLeft);
    //Right border
    pos = new Vector3D(app.width + (borderWidth/2), app.height/2);
    PhysicsRectangle borderRight = new PhysicsRectangle(pos, borderWidth, borderHeight, app, world, 0,0,0, scale);
    borderRight.setName("borderRight");
    parent.addChild(borderRight);
    //Top border
    borderWidth = app.width;
    borderHeight = 50f;
    pos = new Vector3D(app.width/2, -(borderHeight/2));
    PhysicsRectangle borderTop = new PhysicsRectangle(pos, borderWidth, borderHeight, app, world, 0,0,0, scale);
    borderTop.setName("borderTop");
    parent.addChild(borderTop);
    //Bottom border
    pos = new Vector3D(app.width/2 , app.height + (borderHeight/2));
    PhysicsRectangle borderBottom = new PhysicsRectangle(pos, borderWidth, borderHeight, app, world, 0,0,0, scale);
    borderBottom.setName("borderBottom");
    parent.addChild(borderBottom);
  }
 

  @Override
  public void init() {
    this.getMTApplication().registerKeyEvent(this);
  }

  @Override
  public void shutDown() {
    this.getMTApplication().unregisterKeyEvent(this);
  }
 
  public void keyEvent(KeyEvent e){
    int evtID = e.getID();
    if (evtID != KeyEvent.KEY_PRESSED)
      return;
    switch (e.getKeyCode()){
    case KeyEvent.VK_SPACE:
      this.reset();
      break;
      default:
        break;
    }
  }

}
TOP

Related Classes of advanced.physics.scenes.AirHockeyScene$GameFieldHalfDragListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.