⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 weapon.c

📁 Linux游戏编程源码
💻 C
字号:
#include <SDL/SDL.h>#include <math.h>#include <stdio.h>#include <stdlib.h>#include "weapon.h"/* Draws a line from (x0,y0) to (x1,y1) on the given SDL surface.   Assumes that all coordinates are valid. */static void DrawLine16(SDL_Surface *surf, int x0, int y0, int x1, int y1, Uint16 color){    Uint16 *buffer;    int drawpos;    int xspan, yspan;    int xinc, yinc;    int sum;    int i;    /* If we need to lock this surface before drawing pixels, do so. */    if (SDL_MUSTLOCK(surf)) {	if (SDL_LockSurface(surf) < 0) {	    printf("Error locking surface: %s\n", SDL_GetError());	    abort();	}    }    /* Get the surface's data pointer. */    buffer = (Uint16 *)surf->pixels;	    /* Calculate the x and y spans of the line. */    xspan = x1-x0+1;    yspan = y1-y0+1;	    /* Figure out the correct increment for the major axis.       Account for negative spans (x1 < x0, for instance). */    if (xspan < 0) {	xinc = -1;	xspan = -xspan;    } else xinc = 1;    if (yspan < 0) {	yinc = -surf->pitch/2;	yspan = -yspan;    } else yinc = surf->pitch/2;	    i = 0;    sum = 0;	    /* This is our current offset into the buffer. We use this       variable so that we don't have to calculate the offset at       each step; we simply increment this by the correct amount.       Instead of adding 1 to the x coordinate, we add one to drawpos.       Instead of adding 1 to the y coordinate, we add the surface's       pitch (scanline width) to drawpos. */    drawpos = surf->pitch/2 * y0 + x0;	    /* Our loop will be different depending on the       major axis. */    if (xspan < yspan) {	/* Loop through each pixel along the major axis. */	for (i = 0; i < yspan; i++) {	    /* Draw the pixel. */	    buffer[drawpos] = color;	    /* Update the incremental division. */	    sum += xspan;	    /* If we've reached the dividend, advance	       and reset. */	    if (sum >= yspan) {		drawpos += xinc;		sum -= yspan;	    }	    /* Increment the drawing position. */	    drawpos += yinc;	}    } else {	/* See comments above. This code is equivalent. */	for (i = 0; i < xspan; i++) {	    buffer[drawpos] = color;				    sum += yspan;	    if (sum >= xspan) {		drawpos += yinc;		sum -= xspan;	    }	    drawpos += xinc;	}    }    /* Unlock the surface. */    SDL_UnlockSurface(surf);}/* Clips the line from (x0,y0) to (x1,y1) against the given left   and right columns. Returns 1 if the line is at least partially   between the two columns, or 0 if it is completely out of range. */static int ClipLineAgainstVerticals(int *x0, int *y0, int *x1, int *y1,				    int left, int right){    int a, b, c, d;    int hspan, vspan;    /* Handle completely vertical lines. */    if (*x0 == *x1) {	if (*x0 < left || *x0 > right)	    return 0;	return 1;    }    /* If both x coordinates are out of range, the line       is completely invisible. Return 0 to indicate this. */    if (((*x0 < left) && (*x1 < left)) ||	((*x0 > right) && (*x1 > right)))	return 0;    /* Set (a,b) to the leftmost coordinate and (c,d)       to the rightmost. This will simplify the rest of       the routine. */    if (*x0 < *x1) {	a = *x0;	b = *y0;	c = *x1;	d = *y1;    } else {	a = *x1;	b = *y1;	c = *x0;	d = *y0;    }    /* Does the line straddle the left vertical? */    if ((a < left) && (c >= left)) {	hspan = c-a;	vspan = d-b;	a = left;	b = d - (vspan * (c-left)) / hspan;    }    /* Does the line straddle the right vertical? */    if ((a < right) && (c >= right)) {	hspan = c-a;	vspan = d-b;	d = d - (vspan * (c-right)) / hspan;	c = right;    }    /* Final check for validity. */    if ((a < left) || (c > right))	return 0;    /* Pass the clipped coordinates back to the caller. */    *x0 = a;    *y0 = b;    *x1 = c;    *y1 = d;    /* Successful clip. */    return 1;}/* Clips the line from (x0,y0) to (x1,y1) against the given top   and bottom lines. Returns 1 if the line is at least partially   between the two lines, or 0 if it is completely out of range. */static int ClipLineAgainstHorizontals(int *x0, int *y0, int *x1, int *y1,				      int top, int bottom){    int a, b, c, d;    int hspan, vspan;    /* Handle completely horizontal lines. */    if (*y0 == *y1) {	if (*y0 < top || *y0 > bottom)	    return 0;	return 1;    }    /* If both y coordinates are out of range, the line       is completely invisible. Return 0 to indicate this. */    if (((*y0 < top) && (*y1 < top)) ||	((*y0 > bottom) && (*y1 > bottom)))	return 0;    /* Set (a,b) to the topmost coordinate and (c,d)       to the bottommost. This will simplify the rest of       the routine. */    if (*y0 < *y1) {	a = *x0;	b = *y0;	c = *x1;	d = *y1;    } else {	a = *x1;	b = *y1;	c = *x0;	d = *y0;    }    /* Does the line straddle the top line? */    if ((b < top) && (d >= top)) {	hspan = c-a;	vspan = d-b;	b = top;	a = c - (hspan * (d-top)) / vspan;    }    /* Does the line straddle the bottom line? */    if ((b < bottom) && (d >= bottom)) {	hspan = c-a;	vspan = d-b;	c = c - (hspan * (d-bottom)) / vspan;	d = bottom;    }    /* Final check for validity. */    if ((b < top) || (d > bottom))	return 0;    /* Pass the clipped coordinates back to the caller. */    *x0 = a;    *y0 = b;    *x1 = c;    *y1 = d;    /* Successful clip. */    return 1;}/* Clips the line from (x0,y0) to (x1,y1) against the rectangle from   (left,top) to (right,bottom). Returns 1 if the line is visible,   0 if not. */static int ClipLineAgainstRectangle(int *x0, int *y0, int *x1, int *y1,				    int left, int top, int right, int bottom){    if ((ClipLineAgainstHorizontals(x0, y0, x1, y1, top, bottom) == 0) ||	(ClipLineAgainstVerticals(x0, y0, x1, y1, left, right) == 0))	return 0;    return 1;}/* Calculates the starting and ending coordinates of a phaser beam fired   from the given player's position and angle. */static void CalcPhaserBeamCoords(player_p source, int *x0, int *y0, int *x1, int *y1){    *x0 = source->world_x;    *y0 = source->world_y;    *x1 = (int)((double)PHASER_RANGE * cos(source->angle*PI/180.0)) + source->world_x;    *y1 = (int)((double)PHASER_RANGE * -sin(source->angle*PI/180.0)) + source->world_y;}/* Draws a phaser beam as it would be fired from the given player.   vis_x and vis_y give the starting coordinates of the 640x480 area   of the world on the screen. */void DrawPhaserBeam(player_p source, SDL_Surface *surf, int vis_x, int vis_y){    int x0, y0, x1, y1;    CalcPhaserBeamCoords(source, &x0, &y0, &x1, &y1);    x0 -= vis_x;    y0 -= vis_y;    x1 -= vis_x;    y1 -= vis_y;    if (ClipLineAgainstRectangle(&x0, &y0, &x1, &y1, 0, 0,				 SCREEN_WIDTH-1, SCREEN_HEIGHT-1) == 0)	return;    DrawLine16(surf, x0, y0, x1, y1, 0xFFFF);}int CheckPhaserHit(player_p source, player_p target){    float v1x, v1y, v2x, v2y;    float px, py, dist;    int x0, y0, x1, y1;    CalcPhaserBeamCoords(source, &x0, &y0, &x1, &y1);    v1x = x1-x0;    v1y = y1-y0;    v2x = target->world_x - x0;    v2y = target->world_y - y0;    /* If the dot product is less than zero, the target is behind       the source, so there cannot be a hit. */    if (v1x * v2x + v1y * v2y < 0)	return 0;    px = v1x * (v1x * v2x + v1y * v2y) / (v1x * v1x + v1y * v1y);    py = v1y * (v1x * v2x + v1y * v2y) / (v1x * v1x + v1y * v1y);    dist = sqrt((v2x-px)*(v2x-px)+(v2y-py)*(v2y-py));    if (dist < 50)	return 1;    return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -