Bouncing Ball Animation

Started by
4 comments, last by Bacterius 10 years, 5 months ago

Hello! So I've got this assignement from my school to create a Bouncing Ball animation using SDL.

I have been provided a header file which contains an array of all the triangles that make up the ball. Also I have been provided some empty methods that needs implementation.

Each ball must be represented as a separate object data structure (see "object.h" in the zip file). The object data structure contains all variables pertinent to rendering the object on the screen (translation, scale, model coordinates, etc.). Note that the object data structure uses floats to represent translation coordinates. This is to make it easier to handle very small movements (at points, a ball might be moving at a speed less than a pixel). Cast the translation coordinates into integers before drawing the triangles on the screen.

Your code must keep track of objects (balls) by placing the object data structures in a linked list. You need to create your own linked list implementation. Below is a brief description of the object programming interface:

  • CreateObject - Create a new object. The function accepts as input parameters a pointer to the SDL screen, a pointer to a model triangle array, and a variable telling the size of the model triangle array. The function returns a pointer to a new object data structure. The model triangle array specified as input parameter should not be shared across objects. (Not sharing the model triangle array allows e.g. objects to have different colors.) Perform the necessary memory allocation and copying.
  • DestroyObject - Free object. The function accepts as input parameters a pointer to an object data structure. The function should free all memory allocated to represent the object (memory allocated for the model triangle array and the object data structure itself).
  • Drawobject - Draw object on screen. The function accepts as input parameters a pointer to an object data structure. The function must draw the object on the screen by calling DrawTriangle on each of the model triangles. Remember to update scale, translation, etc., in each triangle data structure before invoking DrawTriangle.

This is my assignment. I dont want anyone to post entire code, because I want to learn myself. So far I have 1 single ball on the screen(not moving yet) However I'm having some difficulties with storing the Objects. To make 1 ball i need to iterate with a for loop through the entire triangle array.


int i;
for(i = 0; i < SPHERE_NUMTRIANGLES; i++){
    object = CreateObject(screen,&sphere_model[i],SPHERE_NUMTRIANGLES);			
    DrawObject(object);			
}

This creates 1 ball, but then i need to save my object into a linked list. How do i store my entire object into ONE object? instead of storing each object for each sphere_model? The reason is because i need to create multiple balls to be shown on the screen at once.


object_t *CreateObject(SDL_Surface *screen, triangle_t *model, int numtriangles)
{
    // Implement me
	object_t *object = malloc(sizeof(object_t));
	object->model = malloc(sizeof(triangle_t) * numtriangles);
	object->screen = screen;
	object->ttl = 5000;
	//TODO: ADD RANDOM SPEED
	object->speedx = 10;
	object->speedy = 5;
	object->model = model;
	object->model->scale = 0.1f;
	object->model->tx = screen->w/2.f;
	object->model->ty = 70.0f;
        return object;
Advertisement

You've already got each individual ball in a single object: in the "object_t" type returned by your CreateObject function. That object will contain a pointer to the sphere_model data, as well as other information useful for drawing the ball on the screen.

So now you need to store these ball objects in a linked list, so set up a linked list and insert your balls into it as you go along creating them in your loop. Then when it comes to drawing, you traverse your linked list, going over every ball stored in it, and update/draw them one by one. Are you having problems with the linked list implementation?

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

I see! Thanks. Linked lists are entirely new to us so I'm having a little bit of struggle with that. This is the list.c that was included.


typedef struct listnode listnode_t;
struct listnode {
    listnode_t  *next;
    void        *item;
};

struct list {
    listnode_t *head;
    int numitems;
};

// Create new list
list_t *list_create(void)
{
    // Implement me
    list_t *myHead;
    myHead->next = NULL; <- this is as far as i have gotten with the lists
}

// Free list. items not freed.
void list_destroy(list_t *list)
{
    // Implement me
}

// Insert item first in list
int list_addfirst(list_t *list, void *item)
{
    // Implement me
}

// Insert item last in list.
int list_addlast(list_t *list, void *item)
{
    // Implement me
}

// Remove item from list
void list_remove(list_t *list, void *item)
{
    // Implement me
}

// Return # of items in list
int list_size(list_t *list)
{
    // Implement me
}

/*
 * Iterator implementation
 */

struct list_iterator {
    listnode_t *next;
    list_t *list;
};

// Create new list iterator
list_iterator_t *list_createiterator(list_t *list)
{
    // Implement me
}

// Free iterator
void list_destroyiterator(list_iterator_t *iter)
{
    // Implement me
}

// Move iterator to next item in list and return current.
void *list_next(list_iterator_t *iter)
{
    // Implement me
}

// Let iterator point to first item in list again
void list_resetiterator(list_iterator_t *iter)
{
    // Implement me
}

So, what I do know about lists, is that the head should contain a pointer to the first node? Further, all nodes should contain pointers to the next node? I do have a book on linked lists, but it only has 1 list and not one type for the iterator and one for the node. Any tips perhaps?

Also, in the loop i posted in the first post, does this seem about right?


list_t *myList = list_create();


int i;
for(i = 0; i < SPHERE_NUMTRIANGLES; i++){
    object = CreateObject(screen,&sphere_model[i],SPHERE_NUMTRIANGLES);	
    //save each object into the list
    list_addfirst(myList,object);
   		
}

and in the list.c
list_t *list_create(void){
 
  list_t *myList = (list_t *) malloc(sizeof(list_t));
  mylist->head = NULL;
numitems -> not sure about this one.
}

Regarding the loop, yes, that looks right. For the linked list, the idea is that each element of the list contains two things: the data contained in that element (obviously) and a pointer to the next element. When you've reached the end of the list, the last element points to nothing (i.e. its pointer to the next element is equal to zero, which is a sentinel value). Then you just need to keep track of the first element, and you can get all the elements by simply following the chain of elements using those pointers.

So for instance, how would you add an element to the end of the list? First, you'd find the last element, and then you'd connect its "next" pointer to the element to add.


Before:

Element1 --> Element2 --> Element3 --> 0

After:

Element1 --> Element2 --> Element3 --> NewElement --> 0

Adding to the start of the list is a bit different, since it involves setting the "next" pointer of your new element to point to the element which used to be the first element of the list. You will also need to update the "head" item of your list structure, which is supposed to point to the head of the list (its first element) which you are modifying:


Before:

  Head
   |
   v
Element1 --> Element2 --> Element3 --> 0

After:

  Head
   |
   v
NewElement --> Element1 --> Element2 --> Element3 --> 0

Removal is different. You need to make sure that by deleting an element in the middle of the list, you don't end up losing every element after the one you're deleting, since your chain of "next" pointers will be broken. So you need to "fix up" that chain to go around the missing element, like this:


Before:

Element1 --> Element2 --> Element3 --> 0

After (we are deleting Element2):


          /-----------\
          | (deleted) |
Element1 -- Element2  --> Element3 --> 0

Can you see how to make this work by modifying the "next" pointer of the previous element to the one you're deleting?

The "numitems" variable just keeps track of how many items are in the list at any given time. So this is pretty easy: increment it when you add an item, decrement it when you remove one. And, of course, that makes the implementation of the list_size() function trivial.

As for the iterator functions, think about how you iterate through a linked list: you follow the "next" pointers until you reach an element which points to zero (which indicates it is the last element). So all you need to do to move your iterator forward in list_next() is to do something like:


if (next->next == 0)
{
    // you have reached the end of the list - do something
}
else
{
    // do something with the value contained in the "next" element
    next = next->next; // go to the next element
}

I hope it makes more sense now. Once you have the linked list data structure implemented you can then use it in your program to store and iterate through balls, which I imagine was the goal of the assignment.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”


#include <stdio.h>
#include <stdlib.h>
#include "list.h"


/*
 * List implementation
 */
 
typedef struct listnode listnode_t;
struct listnode {
    listnode_t  *next;
    void        *item;
};

struct list {
    listnode_t *head;
    int numitems;
};
// Create new list
list_t *list_create(void)
{
    // Implement me
	list_t *listHead = (list_t*)malloc(sizeof(list_t));
	
	listHead->head = NULL;
	listHead->numitems = 0;
	
	return listHead;
}
// Free list. items not freed.
void list_destroy(list_t *list)
{
    // Implement me
	free(list);
}
// Insert item first in list
int list_addfirst(list_t *list, void *item)
{	
    // Implement me	
	listnode_t *node = (listnode_t *)malloc(sizeof(listnode_t));
	node->item = item;
	//Set the next element to be the first element
	node->next = list->head;
	list->head = node;
	list->numitems++;	
	
	return 0;
}
// Insert item last in list.
int list_addlast(list_t *list, void *item)
{
    // Implement me
	list->numitems++;
	return 0;
}
// Remove item from list
void list_remove(list_t *list, void *item)
{
    // Implement me
	free(item);
	list->numitems--;
}
// Return # of items in list
int list_size(list_t *list)
{
    // Implement me
	printf("Number of items in list: %d\n",list->numitems);
	return 0;
}
/*
 * Iterator implementation
 */ 
struct list_iterator {
    listnode_t *next;
    list_t *list;
};
// Create new list iterator
list_iterator_t *list_createiterator(list_t *list)
{
    // Implement me
	list_iterator_t *iterator = (list_iterator_t*)malloc(sizeof(list_iterator_t));
	//point the iterator to the first element
	iterator->next = list->head;
	
	return iterator;
}
// Free iterator
void list_destroyiterator(list_iterator_t *iter)
{
    // Implement me
	free(iter);
}
// Move iterator to next item in list and return current.
void *list_next(list_iterator_t *iter)
{
    // Implement me	

	if(iter->next == NULL){
		//end of list
		printf("Reached end of the list");
	}	
	else{
		printf("Going through the list");	
		iter = iter->next;
	}
}
// Let iterator point to first item in list again
void list_resetiterator(list_iterator_t *iter)
{
    // Implement me
	iter->next = iter->list->head;
}

Thanks for all your help so far! I'm having some issue with resetiterator and list_next. When I call resetiterator i get a segment fault and list_next it never moves to the next object in the list.Do you see what i'm doing wrong here?

For list_next, observe that you are actually changing the iterator "iter", not its contents. So what does that mean? Because you are passing the pointer to the iterator by value, changing it will have no effect beyond your list_next() function. Secondly (and your compiler should have warned you about that, crank up your warning level) you are trying to assign iter->next (of type listnode_t*) to iter (of type list_iterator_t*). They are not the same, so assigning one to the other doesn't make a lot of sense.

What you want to do is not change "iter" itself, but change its "next" pointer to move to the next item in the list. How would you do this? Remember that iter->next is a perfectly valid list node (assuming it isn't null, which you've already checked for) so it also has a "next" item...

As for your second issue, note that you have never actually initialized iter->list in your list_createiterator() function.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

This topic is closed to new replies.

Advertisement