[Add] Per pixel collision.

[Fix] Fleets now start at random location.
    -- Still needs improvement.
This commit is contained in:
Allanis 2013-02-08 18:29:07 +00:00
parent 28c5b6ea73
commit acf4150079
12 changed files with 188 additions and 23 deletions

View File

@ -11,9 +11,9 @@ function attack()
target = 0
dir = face(target)
dist = getdist(getpos(target))
if dir < 10 and dist > 100 then
if dir < 10 and dist > 300 then
accel()
elseif dir < 10 and dist < 100 then
elseif dir < 10 and dist < 300 then
shoot()
end
end

View File

@ -164,7 +164,11 @@ void ai_exit(void) {
// Heart of hearts of the ai!! Brains of the pilot.
void ai_think(Pilot* pilot) {
cur_pilot = pilot; // Set current pilot being processed.
pilot_acc = pilot_turn = 0.; // Clean up some variables.
// Clean up some variables.
pilot_acc = pilot_turn = 0.;
//pilot_primary = 0;
if(cur_pilot->task == NULL)
// Idle git!
AI_LCALL("control");

50
src/collision.c Normal file
View File

@ -0,0 +1,50 @@
#include "main.h"
#include "log.h"
#include "collision.h"
// Collide sprite at (asx, asy) int 'at' at pos 'ap' with sprite at (bsx,bsy) in 'bt' at 'bp'
// at - Texture a.
// asx - Position of x of sprite a.
// asy - Position of y of sprite a.
// ap - Position in space of sprite a.
// bt - Texture b.
// bsx - Position of x of sprite b.
// bsy - Position of y of sprite b.
// bp - Position in space of sprite b.
int CollideSprite(const gl_texture* at, const int asx, const int asy, const Vec2* ap,
const gl_texture* bt, const int bsx, const int bsy, const Vec2* bp) {
int x,y;
// a - cube coords.
int ax1 = (int)VX(*ap) - (int)(at->sw)/2;
int ay1 = (int)VY(*ap) - (int)(at->sh)/2;
int ax2 = ax1 + (int)(at->sw) - 1;
int ay2 = ay1 + (int)(at->sh) - 1;
// b - cube coords.
int bx1 = (int)VX(*bp) - (int)(bt->sw)/2;
int by1 = (int)VY(*bp) - (int)(bt->sh)/2;
int bx2 = bx1 + (int)(bt->sw) - 1;
int by2 = by1 + (int)(bt->sh) - 1;
// Check if bounding boxes intersect.
if((bx2 < ax1) || (ax2 < bx1)) return 0;
if((by2 < ay1) || (ay2 < by1)) return 0;
// Define the remaining binding box.
int inter_x0 = MAX(ax1, bx1);
int inter_x1 = MIN(ax2, bx2);
int inter_y0 = MAX(ay1, by1);
int inter_y1 = MIN(ay2, by2);
for(y = inter_y0; y <= inter_y1; y++)
for(x = inter_x0; x <= inter_x1; x++)
// Computer offsets for surface before passing to TransparentPixel test.
if((!gl_isTrans(at, asx*(int)(at->sw) + x-ax1, asy*(int)(at->sh) + y-ay1)) &&
(!gl_isTrans(bt, bsx*(int)(bt->sw) + x-bx1, bsy*(int)(bt->sh) + y-by1)))
return 1;
return 0;
}

7
src/collision.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include "opengl.h"
#include "physics.h"
int CollideSprite(const gl_texture* at, const int asx, const int asy, const Vec2* ap,
const gl_texture* bt, const int bsx, const int bsy, const Vec2* bp);

View File

@ -32,6 +32,8 @@ gl_font gl_defFont;
// Misc.
static int SDL_VFlipSurface(SDL_Surface* surface);
static int SDL_IsTrans(SDL_Surface* s, int x, int y);
static uint8_t* SDL_MapTrans(SDL_Surface* s);
static int pot(int n);
// gl_texture.
static GLuint gl_loadSurface(SDL_Surface* surface, int* rw, int* rh);
@ -76,6 +78,57 @@ static int SDL_VFlipSurface(SDL_Surface* surface) {
return 0;
}
// Return true if position (x,y) of s is transparent.
static int SDL_IsTrans(SDL_Surface* s, int x, int y) {
int bpp = s->format->BytesPerPixel;
// p is the address to the pixel we want to retrieve.
Uint8* p = (Uint8*)s->pixels + y * s->pitch + x*bpp;
Uint32 pixelcolor = 0;
switch(bpp) {
case 1:
pixelcolor = *p;
break;
case 2:
pixelcolor = *(Uint16*)p;
break;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
pixelcolor = p[0] << 16 | p[1] << 8 | p[2];
else
pixelcolor = p[0] | p[1] << 8 | p[2] << 16;
break;
case 4:
pixelcolor = *(Uint32*)p;
break;
}
// Test whetehr the pixels color is equal to color of
//transparent pixels for that surface.
return (pixelcolor == s->format->colorkey);
}
// Map the surface transparancy.
// Return 0 on success.
static uint8_t* SDL_MapTrans(SDL_Surface* s) {
// Allocate memory for just enough bits to hold all the data we need.
int size = s->w*s->h/8 + ((s->w*s->h%8)?1:0);
uint8_t* t = malloc(size);
bzero(t, size); // *must* be set to zero.
if(t == NULL) {
WARN("Out of memeory");
return NULL;
}
int i, j;
for(i = 0; i < s->h; i++)
for(j = 0; j < s->w; j++) // Set each bit to be 1 if not transparent or 0 if it is.
t[(i*s->w+j)/8] |= (SDL_IsTrans(s,j,i)) ? 0 : (1<<((i*s->w+j)%8));
return t;
}
// ================
// TEXTURE!
// ================
@ -187,12 +240,16 @@ gl_texture* gl_loadImage(SDL_Surface* surface) {
texture->sw = texture->w;
texture->sh = texture->h;
texture->trans = NULL;
return texture;
}
// Load the image directly as an opengl texture.
gl_texture* gl_newImage(const char* path) {
SDL_Surface* tmp, *surface;
gl_texture* t;
void* trans = NULL;
uint32_t filesize;
char* buf = pack_readfile(DATA, (char*)path, &filesize);
if(buf == NULL) {
@ -216,11 +273,18 @@ gl_texture* gl_newImage(const char* path) {
SDL_FreeSurface(tmp); // Free the temp surface.
SDL_LockSurface(surface);
trans = SDL_MapTrans(surface);
SDL_UnlockSurface(surface);
if(SDL_VFlipSurface(surface)) {
WARN("Error flipping surface");
return NULL;
}
return gl_loadImage(surface);
t = gl_loadImage(surface);
t->trans = trans;
return t;
}
// Load the texture immediately, but also set is as a sprite.
@ -238,9 +302,26 @@ gl_texture* gl_newSprite(const char* path, const int sx, const int sy) {
// Free the texture.
void gl_freeTexture(gl_texture* texture) {
glDeleteTextures(1, &texture->texture);
if(texture->trans) free(texture->trans);
free(texture);
}
// Return true if pixel at pos (x,y) is transparent.
int gl_isTrans(const gl_texture* t, const int x, const int y) {
return !(t->trans[(y*(int)(t->w)+x)/8] & (1<<((y*(int)(t->w)+x)%8)));
}
// Set x and y to be the appropriate sprite for gl_texture using dir.
void gl_getSpriteFromDir(int* x, int* y, const gl_texture* t, const double dir) {
int s = (int)(dir / (2.0*M_PI / (t->sy*t->sx)));
// Make sure the sprite is "in range".
if(s > (int)(t->sy*t->sx)-1) s = s % (int)(t->sy*t->sx);
*x = s % (int)t->sx;
*y = s / (int)t->sy;
}
// ================
// BLITTING!
// ================

View File

@ -35,6 +35,7 @@ typedef struct {
double sx, sy; // Number of sprites on x and y axes.
double sw, sh; // Size of each sprite.
GLuint texture; // The opengl texture itself.
uint8_t* trans; // Maps the transparency.
} gl_texture;
// Font info.
@ -66,3 +67,7 @@ void gl_print(const gl_font* ft_font, const Vec2* pos, const char* fmt, ...);
int gl_init(void);
void gl_exit(void);
// Misc.
int gl_isTrans(const gl_texture* t, const int x, const int y);
void gl_getSpriteFromDir(int* x, int* y, const gl_texture* t, const double dir);

View File

@ -57,6 +57,13 @@ double vect_angle(const Vec2* ref, const Vec2* v) {
return ANGLE(VX(*v)-VX(*ref), VY(*v)-VY(*ref));
}
void vect_cadd(Vec2* v, const double x, const double y) {
v->x -= x;
v->y -= y;
v->mod = MOD(v->x, v->y);
v->angle = ANGLE(v->x, v->y);
}
// ================
// SOLID!

View File

@ -28,6 +28,7 @@ void vect_pset(Vec2* v, const double mod, const double angle);
void vectcpy(Vec2* dest, const Vec2* src);
void vectnull(Vec2* v);
double vect_angle(const Vec2* ref, const Vec2* v);
void vect_cadd(Vec2* v, const double x, const double y);
// Describe any solid in 2D space.
struct Solid {

View File

@ -120,16 +120,12 @@ void pilot_hit(Pilot* p, const double damage_shield, const double damage_armor)
// Render the pilot.
void pilot_render(Pilot* p) {
int sprite;
gl_texture* t = p->ship->gfx_space;
int sx, sy;
// Get the sprite corresponding to the direction facing.
sprite = (int)(p->solid->dir / (2.0*M_PI / (t->sy * t->sx)));
gl_getSpriteFromDir(&sx, &sy, p->ship->gfx_space, p->solid->dir);
// Ugly hack to make sure it's always "inbound".
if(sprite > (int)(t->sy*t->sx)-1) sprite = (int)(t->sy*t->sx)-1;
gl_blitSprite(t, &p->solid->pos, sprite % (int)t->sx, sprite / (int)t->sy);
gl_blitSprite(p->ship->gfx_space, &p->solid->pos, sx, sy);
}
// Update the pilot.

View File

@ -196,6 +196,8 @@ static PlanetClass planetclass_get(const char a) {
// Init the system.
void space_init(const char* sysname) {
int i, j;
Vec2 v, vn;
for(i = 0; i < nsystems; i++)
if(strcmp(sysname, systems[i].name)==0)
break;
@ -211,17 +213,22 @@ void space_init(const char* sysname) {
stars[i].y = (double)RNG(-STAR_BUF, gl_screen.h + STAR_BUF);
}
// Set up fleets -> pilots.
vectnull(&vn);
for(i = 0; i < cur_system->nfleets; i++)
if(RNG(0,100) <= cur_system->fleets[i].chance) // Check fleet.
if(RNG(0,100) <= cur_system->fleets[i].chance) {// Check fleet.
vect_pset(&v, 2*RNG(MIN_HYPERSPACE_DIST/2, MIN_HYPERSPACE_DIST), RNG(0, 360)*M_PI/180.);
for(j = 0; j < cur_system->fleets[i].fleet->npilots; j++)
if(RNG(0,100) <= cur_system->fleets[i].fleet->pilots[j].chance)
if(RNG(0,100) <= cur_system->fleets[i].fleet->pilots[j].chance) {
vect_cadd(&v, RNG(-50, 50), RNG(-50, 50));
pilot_create(cur_system->fleets[i].fleet->pilots[j].ship,
cur_system->fleets[i].fleet->pilots[j].name,
cur_system->fleets[i].fleet->faction,
RNG(0,360),
NULL,
vect_angle(&v,&vn),
&v,
NULL,
0);
}
}
}
// Load the planets of name 'name'.

View File

@ -1,5 +1,7 @@
#pragma once
#define MIN_HYPERSPACE_DIST 1500
// Load/Exit.
void space_init(const char* sysname);
int space_load(void);

View File

@ -8,6 +8,7 @@
#include "log.h"
#include "rng.h"
#include "pilot.h"
#include "collision.h"
#include "weapon.h"
// Some stuff from pilot.
@ -102,23 +103,27 @@ void weapons_update(const double dt, WeaponLayer layer) {
// Render the weapons.
static void weapon_render(const Weapon* w) {
int sprite;
gl_texture* t = w->outfit->gfx_space;
int sx, sy;
// Get the sprite corresponding to the direction facing.
sprite = (int)(w->solid->dir / (2.0*M_PI / (t->sy*t->sx)));
gl_getSpriteFromDir(&sx, &sy, w->outfit->gfx_space, w->solid->dir);
gl_blitSprite(t, &w->solid->pos, sprite % (int)t->sx, sprite / (int)t->sy);
gl_blitSprite(w->outfit->gfx_space, &w->solid->pos, sx, sy);
}
// Update the weapon.
static void weapon_update(Weapon* w, const double dt, WeaponLayer layer) {
int i;
int i, wsx, wsy, psx, psy;
gl_getSpriteFromDir(&wsx, &wsy, w->outfit->gfx_space, w->solid->dir);
for(i = 0; i < pilots; i++) {
gl_getSpriteFromDir(&psx, &psy, pilot_stack[i]->ship->gfx_space,
pilot_stack[i]->solid->dir);
if((w->parent != pilot_stack[i]->id) && // The pilot hasn't shoot it.
!areAllies(pilot_get(w->parent)->faction, pilot_stack[i]->faction) &&
(DIST(w->solid->pos, pilot_stack[i]->solid->pos) < (PILOT_SIZE_APROX *
w->outfit->gfx_space->sw/2. + pilot_stack[i]->ship->gfx_space->sw/2.))) {
CollideSprite(w->outfit->gfx_space, wsx, wsy, &w->solid->pos,
pilot_stack[i]->ship->gfx_space, psx, psy, &pilot_stack[i]->solid->pos)) {
pilot_hit(pilot_stack[i], w->outfit->damage_shield, w->outfit->damage_armor);
weapon_destroy(w, layer);
return;