📄 wormlet.c
字号:
*/ collisionDetected = food_collision(x , y ) >= 0 || food_collision(x , y + FOOD_SIZE - 1) >= 0 || food_collision(x + FOOD_SIZE - 1, y ) >= 0 || food_collision(x + FOOD_SIZE - 1, y + FOOD_SIZE - 1) >= 0 || argh_collision(x , y ) >= 0 || argh_collision(x , y + FOOD_SIZE - 1) >= 0 || argh_collision(x + FOOD_SIZE - 1, y ) >= 0 || argh_collision(x + FOOD_SIZE - 1, y + FOOD_SIZE - 1) >= 0; /* use coordinates for further testing */ foodx[index] = x; foody[index] = y; /* now test wether we accidently hit the worm with food ;) */ i = 0; for (i = 0; i < worm_count && !collisionDetected; i++) { collisionDetected |= worm_food_collision(&worms[i], index); } } while (collisionDetected); return tries;}/** * Clears a food from the lcd buffer. * @param int index The index of the food arrays under which * the coordinates of the desired food can be found. Ensure * that the value is 0 <= index <= MAX_FOOD. */static void clear_food(int index){ /* remove the old food from the screen */ rb->lcd_clearrect(foodx[index] + FIELD_RECT_X, foody[index] + FIELD_RECT_Y, FOOD_SIZE, FOOD_SIZE);}/** * Draws a food in the lcd buffer. * @param int index The index of the food arrays under which * the coordinates of the desired food can be found. Ensure * that the value is 0 <= index <= MAX_FOOD. */static void draw_food(int index){ /* draw the food object */ rb->lcd_fillrect(foodx[index] + FIELD_RECT_X, foody[index] + FIELD_RECT_Y, FOOD_SIZE, FOOD_SIZE); rb->lcd_clearrect(foodx[index] + FIELD_RECT_X + 1, foody[index] + FIELD_RECT_Y + 1, FOOD_SIZE - 2, FOOD_SIZE - 2);}/** * Find new coordinates for the argh stored in arghx[index], arghy[index] * that don't collide with any other food or argh. * @param int index * Ensure that 0 <= index < argh_count < MAX_ARGH. */static int make_argh(int index){ int x = -1; int y = -1; bool collisionDetected = false; int tries = 0; int i; do { /* make coordinates for a new argh so that the entire food lies within the FIELD */ x = rb->rand() % (FIELD_RECT_WIDTH - ARGH_SIZE); y = rb->rand() % (FIELD_RECT_HEIGHT - ARGH_SIZE); tries ++; /* Ensure that the new argh doesn't intersect with any existing foods or arghs. If one or more corners of the new argh hit any existing argh or food an intersection is detected. */ collisionDetected = food_collision(x , y ) >= 0 || food_collision(x , y + ARGH_SIZE - 1) >= 0 || food_collision(x + ARGH_SIZE - 1, y ) >= 0 || food_collision(x + ARGH_SIZE - 1, y + ARGH_SIZE - 1) >= 0 || argh_collision(x , y ) >= 0 || argh_collision(x , y + ARGH_SIZE - 1) >= 0 || argh_collision(x + ARGH_SIZE - 1, y ) >= 0 || argh_collision(x + ARGH_SIZE - 1, y + ARGH_SIZE - 1) >= 0; /* use the candidate coordinates to make a real argh */ arghx[index] = x; arghy[index] = y; /* now test wether we accidently hit the worm with argh ;) */ for (i = 0; i < worm_count && !collisionDetected; i++) { collisionDetected |= worm_argh_collision(&worms[i], index); collisionDetected |= worm_argh_collision_in_moves(&worms[i], index, MIN_ARGH_DIST); } } while (collisionDetected); return tries;}/** * Draws an argh in the lcd buffer. * @param int index The index of the argh arrays under which * the coordinates of the desired argh can be found. Ensure * that the value is 0 <= index < argh_count <= MAX_ARGH. */static void draw_argh(int index){ /* draw the new argh */ rb->lcd_fillrect(arghx[index] + FIELD_RECT_X, arghy[index] + FIELD_RECT_Y, ARGH_SIZE, ARGH_SIZE);}static void virtual_player(struct worm *w);/** * Initialzes the specified worm with INITIAL_WORM_LENGTH * and the tail at the specified position. The worm will * be initialized alive and creeping EAST. * @param struct worm *w The worm that is to be initialized * @param int x The x coordinate at which the tail of the worm starts. * x must be 0 <= x < FIELD_RECT_WIDTH. * @param int y The y coordinate at which the tail of the worm starts * y must be 0 <= y < FIELD_RECT_WIDTH. */static void init_worm(struct worm *w, int x, int y){ /* initialize the worm size */ w->head = 1; w->tail = 0; w->x[w->head] = x + 1; w->y[w->head] = y; w->x[w->tail] = x; w->y[w->tail] = y; /* set the initial direction the worm creeps to */ w->dirx = 1; w->diry = 0; w->growing = INITIAL_WORM_LENGTH - 1; w->alive = true; w->fetch_worm_direction = virtual_player;}/** * Writes the direction that was stored for * human player 1 into the specified worm. This function * may be used to be stored in worm.fetch_worm_direction. * The value of * the direction is read from player1_dir. * @param struct worm *w - The worm of which the direction * is altered. */static void human_player1(struct worm *w) { set_worm_dir(w, player1_dir);}/** * Writes the direction that was stored for * human player 2 into the specified worm. This function * may be used to be stored in worm.fetch_worm_direction. * The value of * the direction is read from player2_dir. * @param struct worm *w - The worm of which the direction * is altered. */static void human_player2(struct worm *w) { set_worm_dir(w, player2_dir);}/** * Writes the direction that was stored for * human player using a remote control * into the specified worm. This function * may be used to be stored in worm.fetch_worm_direction. * The value of * the direction is read from player3_dir. * @param struct worm *w - The worm of which the direction * is altered. */static void remote_player(struct worm *w) { set_worm_dir(w, player3_dir);}/** * Initializes the worm-, food- and argh-arrays, draws a frame, * makes some food and argh and display all that stuff. */static void init_wormlet(void){ int i; for (i = 0; i< worm_count; i++) { /* Initialize all the worm coordinates to center. */ int x = (int)(FIELD_RECT_WIDTH / 2); int y = (int)((FIELD_RECT_HEIGHT - 20)/ 2) + i * 10; init_worm(&worms[i], x, y); } player1_dir = EAST; player2_dir = EAST; player3_dir = EAST; if (players > 0) { worms[0].fetch_worm_direction = human_player1; } if (players > 1) { if (use_remote) { worms[1].fetch_worm_direction = remote_player; } else { worms[1].fetch_worm_direction = human_player2; } } if (players > 2) { worms[2].fetch_worm_direction = human_player2; } /* Needed when the game is restarted using BUTTON_ON */ rb->lcd_clear_display(); /* make and display some food and argh */ argh_count = MAX_FOOD; for (i = 0; i < MAX_FOOD; i++) { make_food(i); draw_food(i); make_argh(i); draw_argh(i); } /* draw the game field */ rb->lcd_invertrect(0, 0, FIELD_RECT_WIDTH + 2, FIELD_RECT_HEIGHT + 2); rb->lcd_invertrect(1, 1, FIELD_RECT_WIDTH, FIELD_RECT_HEIGHT); /* make everything visible */ rb->lcd_update();}/** * Move the worm one step further if it is alive. * The direction in which the worm moves is taken from dirx and diry. * move_worm decreases growing if > 0. While the worm is growing the tail * is left untouched. * @param struct worm *w The worm to move. w must not be NULL. */static void move_worm(struct worm *w){ if (w->alive) { /* determine the head point and its precessor */ int headx = w->x[w->head]; int heady = w->y[w->head]; int prehead = (w->head + MAX_WORM_SEGMENTS - 1) % MAX_WORM_SEGMENTS; int preheadx = w->x[prehead]; int preheady = w->y[prehead]; /* determine the old direction */ int olddirx; int olddiry; if (headx == preheadx) { olddirx = 0; olddiry = (heady > preheady) ? 1 : -1; } else { olddiry = 0; olddirx = (headx > preheadx) ? 1 : -1; } /* olddir == dir? a change of direction means a new segment has been opened */ if (olddirx != w->dirx || olddiry != w->diry) { w->head = (w->head + 1) % MAX_WORM_SEGMENTS; } /* new head position */ w->x[w->head] = headx + w->dirx; w->y[w->head] = heady + w->diry; /* while the worm is growing no tail procession is necessary */ if (w->growing > 0) { /* update the worms grow state */ w->growing--; } /* if the worm isn't growing the tail has to be dragged */ else { /* index of the end of the tail segment */ int tail_segment_end = (w->tail + 1) % MAX_WORM_SEGMENTS; /* drag the end of the tail */ /* only one coordinate has to be altered. Here it is determined which one */ int dir = 0; /* specifies wether the coord has to be in- or decreased */ if (w->x[w->tail] == w->x[tail_segment_end]) { dir = (w->y[w->tail] - w->y[tail_segment_end] < 0) ? 1 : -1; w->y[w->tail] += dir; } else { dir = (w->x[w->tail] - w->x[tail_segment_end] < 0) ? 1 : -1; w->x[w->tail] += dir; } /* when the tail has been dragged so far that it meets the next segment start the tail segment is obsolete and must be freed */ if (w->x[w->tail] == w->x[tail_segment_end] && w->y[w->tail] == w->y[tail_segment_end]){ /* drop the last tail point */ w->tail = tail_segment_end; } } }}/** * Draws the head and clears the tail of the worm in * the display buffer. lcd_update() is NOT called thus * the caller has to take care that the buffer is displayed. */static void draw_worm(struct worm *w){ /* draw the new head */ int x = w->x[w->head]; int y = w->y[w->head]; if (x >= 0 && x < FIELD_RECT_WIDTH && y >= 0 && y < FIELD_RECT_HEIGHT) { rb->lcd_drawpixel(x + FIELD_RECT_X, y + FIELD_RECT_Y); } /* clear the space behind the worm */ x = w->x[w->tail] ; y = w->y[w->tail] ; if (x >= 0 && x < FIELD_RECT_WIDTH && y >= 0 && y < FIELD_RECT_HEIGHT) { rb->lcd_clearpixel(x + FIELD_RECT_X, y + FIELD_RECT_Y); }}/** * Checks wether the coordinate is part of the worm. Returns * true if any part of the worm was hit - including the head. * @param x int The x coordinate * @param y int The y coordinate * @return int The index of the worm arrays that contain x, y. * Returns -1 if the coordinates are not part of the worm. */ static int specific_worm_collision(struct worm *w, int x, int y){ int retVal = -1; /* get_worm_array_length is expensive -> buffer the value */ int wormLength = get_worm_array_length(w); int i; /* test each entry that is part of the worm */ for (i = 0; i < wormLength && retVal == -1; i++) { /* The iteration iterates the length of the worm. Here's the conversion to the true indices within the worm arrays. */ int linestart = (w->tail + i ) % MAX_WORM_SEGMENTS; int lineend = (linestart + 1) % MAX_WORM_SEGMENTS; bool samex = (w->x[linestart] == x) && (w->x[lineend] == x); bool samey = (w->y[linestart] == y) && (w->y[lineend] == y); if (samex || samey){ int test, min, max, tmp; if (samey) { min = w->x[linestart]; max = w->x[lineend]; test = x; } else { min = w->y[linestart]; max = w->y[lineend]; test = y; } tmp = min; min = MIN(min, max); max = MAX(tmp, max); if (min <= test && test <= max) { retVal = lineend; } } } return retVal;}/** * Increases the length of the specified worm by marking * that it may grow by len pixels. Note that the worm has * to move to make the growing happen. * @param worm *w The worm that is to be altered. * @param int len A positive value specifying the amount of * pixels the worm may grow. */static void add_growing(struct worm *w, int len) { w->growing += len;}/** * Determins the worm that is at the coordinates x, y. The parameter * w is a switch parameter that changes the functionality of worm_collision. * If w is specified and x,y hits the head of w NULL is returned. * This is a useful way to determine wether the head of w hits * any worm but including itself but excluding its own head. * (It hits always its own head ;)) * If w is set to NULL worm_collision returns any worm including all heads * that is at position of x,y. * @param struct worm *w The worm of which the head should be excluded in * the test. w may be set to NULL. * @param int x The x coordinate that is checked * @param int y The y coordinate that is checkec * @return struct worm* The worm that has been hit by x,y. If no worm * was at the position NULL is returned. */static struct worm* worm_collision(struct worm *w, int x, int y){ struct worm *retVal = NULL; int i; for (i = 0; (i < worm_count) && (retVal == NULL); i++) { int collision_at = specific_worm_collision(&worms[i], x, y); if (collision_at != -1) { if (!(w == &worms[i] && collision_at == w->head)){ retVal = &worms[i]; } } } return retVal;}/** * Returns true if the head of the worm just has * crossed the field boundaries. * @return bool true if the worm just has wrapped. */ static bool field_collision(struct worm *w){ bool retVal = false; if ((w->x[w->head] >= FIELD_RECT_WIDTH) || (w->y[w->head] >= FIELD_RECT_HEIGHT) || (w->x[w->head] < 0) || (w->y[w->head] < 0)) { retVal = true; } return retVal;}/** * Returns true if the specified coordinates are within the * field specified by the FIELD_RECT_XXX constants. * @param int x The x coordinate of the point that is investigated * @param int y The y coordinate of the point that is investigated * @return bool Returns false if x,y specifies a point outside the * field of worms. */static bool is_in_field_rect(int x, int y) { bool retVal = false; retVal = (x >= 0 && x < FIELD_RECT_WIDTH && y >= 0 && y < FIELD_RECT_HEIGHT); return retVal;}/** * Checks and returns wether the head of the w * is colliding with something currently. * @return int One of the values: * COLLISION_NONE * COLLISION_w * COLLISION_FOOD * COLLISION_ARGH * COLLISION_FIELD */static int check_collision(struct worm *w){ int retVal = COLLISION_NONE; if (worm_collision(w, w->x[w->head], w->y[w->head]) != NULL) retVal = COLLISION_WORM; if (food_collision(w->x[w->head], w->y[w->head]) >= 0) retVal = COLLISION_FOOD; if (argh_collision(w->x[w->head], w->y[w->head]) >= 0) retVal = COLLISION_ARGH; if (field_collision(w)) retVal = COLLISION_FIELD; return retVal;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -