defender.c
来自「开发linux应用-用gtk+和gdk开发linux图形用户界面应用--的实例」· C语言 代码 · 共 1,642 行 · 第 1/3 页
C
1,642 行
* --- This missile has a life, when it goes to zero, * it gets destroyed. */ missile->life = 60; return (missile);}/* * AddExplosion * * A unit was destroyed - we create an explosion at the * unit's location */void AddExplosion (typUnit *unit){ typUnit *frag; int i; /* --- Creating eight fragments --- */ for (i = 0; i < 8; i++) { /* --- Create a fragment of the explosion --- */ frag = (typUnit *) g_malloc (sizeof (typUnit)); /* --- Initialize the fragment --- */ frag->bDestroy = FALSE; frag->pctFiring = 0; frag->type = EXPLOSION; frag->x = unit->x; frag->y = unit->y; /* --- Moves quite fast --- */ frag->vx = x_exp[i] * 5; frag->vy = y_exp[i] * 5; frag->lockunit = NULL; /* --- Short life --- */ frag->life = 20; /* --- Add it to the list of units --- */ unitList = g_list_append (unitList, frag); }}/* * PlaceAliens * * Create the aliens. */void PlaceAliens (){ int i; typUnit *alien; /* --- Create each of the aliens --- */ for (i = 0; i < START_ALIENS; i++) { /* --- Create one alien --- */ alien = CreateAlien (); /* --- Add it to the units list --- */ unitList = g_list_append (unitList, alien); }}/* * DistanceBetween * * Calculate the distance between two units - but * only use the X direction to calculate the distance. * The distance is not just the difference between * the units X coordinates, but since the world * wraps around, we have to consider the fact that * the distance between 1 and X_RANGE - 1 is not * (X_RANGE-1) - 1 */int DistanceBetween (typUnit *u1, typUnit *u2){ int nDistance; int nDistance2; /* --- Figure out which is greater --- */ if (u1->x < u2->x) { /* --- Calculate distance both ways --- */ nDistance = u2->x - u1->x; nDistance2 = X_RANGE + u1->x - u2->x; } else { /* --- Calculate distance both ways --- */ nDistance = u1->x - u2->x; nDistance2 = X_RANGE + u2->x - u1->x; } /* --- Pick smaller of the distances --- */ return ((nDistance < nDistance2) ? nDistance : nDistance2);}/* * Direction * * What is the -x- directory between the two units? * It's either going to be -1, 1, or 0. */int Direction (typUnit *u1, typUnit *u2){ int nDistance; int nDistance2; if (u1->x < u2->x) { /* --- Distance each way --- */ nDistance = u2->x - u1->x; nDistance2 = X_RANGE + u1->x - u2->x; } else { /* --- Distance each way --- */ nDistance2 = u1->x - u2->x; nDistance = X_RANGE + u2->x - u1->x; } /* --- Direction depends on closer distance --- */ return ((nDistance < nDistance2) ? 1 : -1);}/* * AttemptFiring * * Have the alien fire at the hero. */void AttemptFiring (typUnit *unit){ typUnit *missile; /* --- Close enough to shoot at --- */ if (DistanceBetween (hero, unit) < (nScreenWidth / 2)) { /* --- Random chance - less than unit's chance --- */ if ((rand () % 100) < unit->pctFiring) { /* --- Create the missle going after the hero --- */ missile = CreateMissile (unit, hero); /* --- Add to the list of units --- */ unitList = g_list_append (unitList, missile); } }}/* * AIModule * * Contains the logic for each of the units to move. * Some units like landers are looking for people to * pick up. Mutuants hunt down the player. Missiles * just go until they die, etc. */void AIModule (typUnit *unit){ typUnit *tmp; int bestdist = 50000; typUnit *closest = NULL; GList *node; /* * Alien lander AI logic */ if (unit->type == LANDER) { /* --- if the alien's locked on a person --- */ if (unit->lockunit) { /* --- Move it up. --- */ closest = unit->lockunit; unit->y -= .5; closest->y -= .5; /* --- If alien's made it to the top --- */ if (unit->y - (sprite_lander[0].height / 2) < RADAR_HEIGHT) { /* --- Assimilate human! --- */ unit->y = RADAR_HEIGHT + (sprite_lander[0].height / 2); unit->type = MUTANT; unit->pctFiring = MUTANT_TRIGGER_PCT; unit->lockunit = NULL; closest->bDestroy = TRUE; } return; } /* --- Any people nearby to snatch? --- */ for (node = unitList; node; node = node->next) { tmp = (typUnit *) node->data; if (tmp->type == PERSON && tmp->lockunit == NULL) { /* --- Look for a closer person --- */ if (DistanceBetween (unit, tmp) < bestdist) { closest = tmp; bestdist = DistanceBetween (unit, tmp); } } } /* --- We're locked onto a target --- */ if (bestdist <= 1) { /* --- Scootch it over a bit --- */ unit->vx = 0; unit->x = closest->x; /* * --- Check for a lock... --- */ if ((unit->y + (sprite_lander[0].height / 2) + .8) < (closest->y - (sprite_man[0].height / 2))) { /* --- Come down on it. --- */ unit->y += .5; } else if ((unit->y + (sprite_lander[0].height / 2)) > (closest->y - (sprite_man[0].height / 2))) { unit->y -= .5; } else { /* --- Lock it in --- */ unit->lockunit = closest; closest->lockunit = unit; closest->life = 20; } /* --- Anything in reasonable range? --- */ } else if (bestdist < 20) { /* --- Move towards it --- */ unit->vx = Direction (unit, closest); unit->x += unit->vx; } else { /* * --- Nothing nearby. Move in a random direction. */ if (unit->vx == 0) { if ((rand () % 2) == 0) { unit->vx = 1; } else { unit->vx = -1; } } unit->x += unit->vx; } /* * See if there is anything worth shooting at. */ AttemptFiring (unit); /* * Mutant AI logic */ } else if (unit->type == MUTANT) { /* * --- Lets go crazy. Mutant moves almost randomly yet * slowly towards the player. */ unit->vx = Direction (unit, hero) * ((rand () % 4) + 1); unit->vy = rand () % 5 - 2; /* * If the hero is within smelling distance, move towards * player in the -y- direction. */ if (DistanceBetween (unit, hero) < 200) { if (unit->y < hero->y) unit->vy++; if (unit->y > hero->y) unit->vy--; } /* --- Finally move the unit --- */ Move (unit); /* --- Let the mutant attempt firing --- */ AttemptFiring (unit); /* * --- Missiles and explosions */ } else if ((unit->type == MISSILE) || (unit->type == EXPLOSION)) { /* --- These have a life. Decrement it. --- */ unit->life --; /* --- Move it. --- */ Move (unit); /* --- When it reaches zero, destroy it --- */ if (unit->life <= 0) { unit->bDestroy = TRUE; } /* * Person AI. */ } else if (unit->type == PERSON) { /* * Only time person moves by itself is when it's falling * from the sky after the alien carrying it has been shot. */ if (unit->lockunit == NULL && unit->y < PERSON_HEIGHT) { /* --- Move it down --- */ unit->y += 2; } }}/* * GetSprite * * Get the sprite for the unit. */typSprite *GetSprite (typUnit *unit){ typSprite *sprite; /* --- Get sprite --- */ switch (unit->type) { case HERO: sprite = sprite_ship; break; case PERSON: sprite = sprite_man; break; case LANDER: sprite = sprite_lander; break; case MUTANT: sprite = sprite_mutant; break; case MISSILE: case EXPLOSION: sprite = sprite_missile; break; default: sprite = NULL; break; } return (sprite);}/* * AnyoneBetween * * Is any unit between these coordinates? Used by the * laser when computing if anything has been hit. */typUnit *AnyoneBetween (int x1, int y1, int x2, int y2){ GList *node; typUnit *unit; typUnit *closestUnit = NULL; int closestX; typSprite *sprite; int screenX; /* --- Check each unit --- */ for (node = unitList; node; node = node->next) { unit = (typUnit *) node->data; /* --- if it's a bad guy --- */ if ((unit->type == LANDER) || (unit->type == PERSON) || (unit->type == MUTANT)) { /* --- Get sprite and screen position --- */ screenX = UnitScreenX (unit); sprite = GetSprite (unit); /* --- If we have a sprite --- */ if (sprite) { /* --- If in range using -x- --- */ if ((screenX >= x1 && screenX <= x2) || (screenX <= x1 && screenX >= x2)) { /* --- And in range using -y- --- */ if ((unit->y - (sprite->height / 2) < y1) && unit->y + (sprite->height / 2) > y1) { /* * Haven't found a unit or this one * is closer. */ if ((closestUnit == NULL) || (abs (x1 - screenX) < abs (x1 - closestX))) { /* --- This is closst so far --- */ closestUnit = unit; closestX = screenX; } } } } } } return (closestUnit);}/* * UnitTop * * Calculate the maximum height of the unit based on the * radar screen and the sprite size. */int UnitTop (typUnit *unit){ typSprite *sprite; /* --- Get the sprite --- */ sprite = GetSprite (unit); /* --- Add 1/2 sprite size to radar size. --- */ return (RADAR_HEIGHT + (sprite[0].height / 2));}/* * UnitBottom * * Calculate how low the unit can appear on the screen. * It's partially based on the unit's size. */int UnitBottom (typUnit *unit){ typSprite *sprite; sprite = GetSprite (unit); return (GetGameHeight () - (sprite[0].height / 2));}/* * */void AdjustSpriteHeight (typUnit *unit){ typSprite *sprite; int nTop; int nBottom; /* --- Get the sprite for the unit --- */ sprite = GetSprite (unit); if (sprite == NULL) return; /* --- Calculate the top and bottom range of unit --- */ nTop = UnitTop (unit); nBottom = UnitBottom (unit); /* --- Don't let them go too high or too low --- */ if (unit->y < nTop) { unit->y = nTop; } else if (unit->y > nBottom) { unit->y = nBottom; }}/* * DisplayOtherUnits * * Display all the units on the screen. First, we need * to move each of the units to their new positions. * Some of this is done in the AI module. * */void DisplayOtherUnits (GdkPixmap *pixmap, GtkWidget *drawing_area){ typUnit *unit; typUnit *unitHit; GList *node; int xPos; int xPosEnd; typSprite *sprite; /* --- Each unit in the list --- */ for (node = unitList; node; node = node->next) { /* --- Get the unit --- */ unit = (typUnit *) node->data; /* * --- Run the AI module on it to move it --- */ AIModule (unit); /* * If the unit was destroyed by the AI, * don't draw the unit. */ if (unit->bDestroy) { continue; } /* * If there's no sprite for the unit, * we can't draw it now, can we? */ sprite = GetSprite (unit); if (sprite == NULL) continue; /* --- Where on the screen is it going? --- */ xPos = UnitScreenX (unit); /* --- Make sure unit doesn't go out of bounds --- */ AdjustSpriteHeight (unit); /* --- Finally draw unit --- */ DisplaySprite (drawing_area, sprite, (int) (xPos - sprite[0].width / 2), (int) (unit->y - sprite[0].height / 2)); } /* * --- once everyone is painted, fire the lasers. */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?