Page 1 of 1

Are cpBody automaticall collidable?

Posted: Wed Oct 30, 2013 4:03 pm
by Munchor
I've used Chipmunk JS before and my cpBodies would automatically collide would each other. However, I'm now trying the C version using Allegro to display items and I'm not really being able to make my cpBodies collide against each other.

Here is my full source code:

Code: Select all

#include <stdio.h>
#include <allegro5/allegro.h>
#include <chipmunk/chipmunk.h>

const float FPS = 60.0;
const int SCREEN_W = 640;
const int SCREEN_H = 480;
const int BOUNCER_SIZE = 32;
int keys[ALLEGRO_KEY_MAX];
cpVect mouse;
cpBody *blocks[32];
cpSpace *space;
int n_blocks;

void add_block()
{
  cpFloat radius = 5;
  cpFloat mass = 1;
  cpFloat moment = cpMomentForCircle(mass, 0, radius, cpvzero);

  cpBody *newBody = cpSpaceAddBody(space, cpBodyNew(mass, moment));
  cpBodySetPos(newBody, cpv(mouse.x, mouse.y));

  cpShape *newShape = cpSpaceAddShape(space, cpCircleShapeNew(newBody,
                                                              radius,
                                                              cpvzero));

  cpShapeSetFriction(newShape, 1);

  blocks[n_blocks++] = newBody;
}

int main(int argc, char **argv)
{
  mouse = cpv(0, 0);
  cpVect gravity = cpv(0, 100);

  space = cpSpaceNew();
  cpSpaceSetGravity(space, gravity);

  cpShape *ground = cpSegmentShapeNew(space->staticBody, cpv(0, 300),
                                      cpv(300, 300), 0);
  cpShapeSetFriction(ground, 1);
  cpSpaceAddShape(space, ground);

  n_blocks = 0;

  cpFloat timeStep = 1.0 / FPS;

  ALLEGRO_DISPLAY *display = NULL;
  ALLEGRO_EVENT_QUEUE *event_queue = NULL;
  ALLEGRO_TIMER *timer = NULL;
  ALLEGRO_BITMAP *bouncer = NULL;
  bool redraw = true;
  bool doexit = false;

  if (!al_init()) {
    fprintf(stderr, "Failed to initialize allegro!\n");
    return -1;
  }

  if (!al_install_keyboard()) {
    fprintf(stderr, "Failed to initialize the keyboard!\n");
    return -1;
  }

  if (!al_install_mouse()) {
    fprintf(stderr, "Failed to initialize the mouse!\n");
    return -1;
  }

  timer = al_create_timer(1.0 / FPS);
  if (!timer) {
    fprintf(stderr, "Failed to create timer!\n");
    return -1;
  }

  display = al_create_display(SCREEN_W, SCREEN_H);
  if (!display) {
    fprintf(stderr, "Failed to create display!\n");
    al_destroy_timer(timer);
    return -1;
  }

  bouncer = al_create_bitmap(BOUNCER_SIZE, BOUNCER_SIZE);
  if (!bouncer) {
    fprintf(stderr, "Failed to create bouncer bitmap!\n");
    al_destroy_display(display);
    al_destroy_timer(timer);
    return -1;
  }

  al_set_target_bitmap(bouncer);
  al_clear_to_color(al_map_rgb(255, 0, 255));
  al_set_target_bitmap(al_get_backbuffer(display));

  event_queue = al_create_event_queue();
  if (!event_queue) {
    fprintf(stderr, "Failed to create event_queue!\n");
    al_destroy_bitmap(bouncer);
    al_destroy_display(display);
    al_destroy_timer(timer);
    return -1;
  }

  al_register_event_source(event_queue, al_get_display_event_source(display));
  al_register_event_source(event_queue, al_get_timer_event_source(timer));
  al_register_event_source(event_queue, al_get_mouse_event_source());
  al_register_event_source(event_queue, al_get_keyboard_event_source());
  al_clear_to_color(al_map_rgb(0,0,0));
  al_flip_display();
  al_start_timer(timer);

  while (!doexit)
  {
    cpSpaceStep(space, timeStep);
    //cpVect pos = cpBodyGetPos(ballBody);

    ALLEGRO_EVENT ev;
    al_wait_for_event(event_queue, &ev);

    if (ev.type == ALLEGRO_EVENT_TIMER) {
      if (keys[ALLEGRO_KEY_LEFT]) {
        //pos.x -= 2;
        //cpBodySetPos(ballBody, pos);
      }

      if (keys[ALLEGRO_KEY_RIGHT]) {
        //pos.x += 2;
        //cpBodySetPos(ballBody, pos);
      }

      redraw = true;
    } else if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
      break;
    } else if (ev.type == ALLEGRO_EVENT_KEY_DOWN) {
      keys[ev.keyboard.keycode] = true;
    } else if (ev.type == ALLEGRO_EVENT_KEY_UP) {
      keys[ev.keyboard.keycode] = false;
    } else if (ev.type == ALLEGRO_EVENT_MOUSE_AXES ||
               ev.type == ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY) {
      mouse.x = ev.mouse.x;
      mouse.y = ev.mouse.y;
    } else if (ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) {
      add_block();
    }

    if (redraw && al_is_event_queue_empty(event_queue)) {
      redraw = false;
      al_clear_to_color(al_map_rgb(0, 0, 0));

      int i;
      for (i = 0; i < n_blocks; i++) {
        cpVect pos = cpBodyGetPos(blocks[i]);
        al_draw_bitmap(bouncer, pos.x, pos.y, 0);
      }

      al_flip_display();
    }
  }

  al_destroy_bitmap(bouncer);
  al_destroy_timer(timer);
  al_destroy_display(display);
  al_destroy_event_queue(event_queue);

  cpShapeFree(ground);
  cpSpaceFree(space);

  return 0;
}
Basically, I use the mouse to add new blocks to the screen and they should fall on top of each other. Instead they all just collide with the ground and not with each other.

Besides, I wonder if in Chipmunk the X and Y coordinates of bodies and shapes are the center of the object or the top left corner or something else. I couldn't find much information on that.

Any ideas? Thank you in advance.

Edit: I put up a better version of the source code here.

Re: Are cpBody automaticall collidable?

Posted: Thu Oct 31, 2013 3:15 am
by Munchor
Alright, I reckon I got it:

Code: Select all

void add_block()
{
  cpFloat radius = 5;
  cpFloat mass = 1;
  cpFloat moment = cpMomentForBox(mass, 32, 32);

  cpBody *newBody = cpSpaceAddBody(space, cpBodyNew(mass, moment));
  cpBodySetPos(newBody, cpv(mouse.x, mouse.y));

  cpShape *newShape = cpSpaceAddShape(space, cpBoxShapeNew(newBody,
                                                           32, 32));

  cpShapeSetFriction(newShape, 1);

  blocks[n_blocks++] = newBody;
}
I just had to change to using a Box, not a CircleShape and cpMomentForBox as opposed to cpMomentForCircle.

Much better now, but I still have to fix my angle when drawing. I'll try and figure out how I can get the angle of a cpBody.

Re: Are cpBody automaticall collidable?

Posted: Sun Nov 03, 2013 9:50 am
by slembcke
cpBodyGetAngle(body) returns the rotation of the body in radians. If you don't want the box to rotate, you can give it INFINITY for the moment of inertia.