Shoot Astroid
Simple Astroids clone
Published
Liked the article? Share it!
We add in hit detection for the astroids coming in contact with the player bullets. To start off, if a hit is detected we simply toggle the astroid off for debug purposes.
main.c
#include <epoxy/gl.h>
#include <epoxy/glx.h>
#include <gtk/gtk.h>
#include <math.h>
#include "DashGL/dashgl.h"
static void on_realize(GtkGLArea *area);
static void on_render(GtkGLArea *area, GdkGLContext *context);
static gboolean on_idle(gpointer data);
static gboolean on_keydown(GtkWidget *widget, GdkEventKey *event);
static gboolean on_keyup(GtkWidget *widget, GdkEventKey *event);
#define NUM_BULLETS 10
#define WIDTH 640.0f
#define HEIGHT 480.0f
#define NUM_ROCKS 3
GLuint program;
GLuint vao;
GLint attribute_texcoord, attribute_coord2d;
GLint uniform_mytexture, uniform_mvp;
struct bullet {
vec3 pos;
GLfloat rot;
gboolean active;
int ticks;
};
struct {
GLuint vbo[2];
GLuint tex[2];
vec3 pos;
mat4 mvp;
gboolean left;
gboolean right;
gboolean up;
gboolean space;
GLfloat rot;
GLfloat dx, dy, max;
float bullet_speed;
int num_ticks;
struct bullet bullets[NUM_BULLETS];
} player;
struct rock {
vec3 pos;
float rot;
float dx, dy;
int size;
gboolean active;
};
struct {
GLuint vbo;
GLuint tex;
mat4 mvp;
float radius;
struct rock rocks[NUM_ROCKS];
} astroid;
int main(int argc, char *argv[]) {
GtkWidget *window;
GtkWidget *glArea;
gtk_init(&argc, &argv);
// Initialize Window
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "Astroids Tutorial");
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 640, 480);
gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_UTILITY);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(window, "key-press-event", G_CALLBACK(on_keydown), NULL);
g_signal_connect(window, "key-release-event", G_CALLBACK(on_keyup), NULL);
// Initialize GTK GL Area
glArea = gtk_gl_area_new();
gtk_widget_set_vexpand(glArea, TRUE);
gtk_widget_set_hexpand(glArea, TRUE);
g_signal_connect(glArea, "realize", G_CALLBACK(on_realize), NULL);
g_signal_connect(glArea, "render", G_CALLBACK(on_render), NULL);
gtk_container_add(GTK_CONTAINER(window), glArea);
// Show widgets
gtk_widget_show_all(window);
gtk_main();
return 0;
}
static void on_realize(GtkGLArea *area) {
// Debug Message
int i;
g_print("on realize\n");
gtk_gl_area_make_current(area);
if(gtk_gl_area_get_error(area) != NULL) {
fprintf(stderr, "Unknown error\n");
return;
}
const GLubyte *renderer = glGetString(GL_RENDER);
const GLubyte *version = glGetString(GL_VERSION);
printf("Renderer: %s\n", renderer);
printf("OpenGL version supported %s\n", version);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLfloat player_vertices[] = {
-24.0, -24.0, 0.0, 0.0,
-24.0, 24.0, 0.0, 1.0,
24.0, 24.0, 1.0, 1.0,
-24.0, -24.0, 0.0, 0.0,
24.0, 24.0, 1.0, 1.0,
24.0, -24.0, 1.0, 0.0
};
glGenBuffers(1, &player.vbo[0]);
glBindBuffer(GL_ARRAY_BUFFER, player.vbo[0]);
glBufferData(
GL_ARRAY_BUFFER,
sizeof(player_vertices),
player_vertices,
GL_STATIC_DRAW
);
GLfloat bullet_vertices[] = {
-8.0, -8.0, 0.0, 0.0,
-8.0, 8.0, 0.0, 1.0,
8.0, 8.0, 1.0, 1.0,
-8.0, -8.0, 0.0, 0.0,
8.0, 8.0, 1.0, 1.0,
8.0, -8.0, 1.0, 0.0
};
glGenBuffers(1, &player.vbo[1]);
glBindBuffer(GL_ARRAY_BUFFER, player.vbo[1]);
glBufferData(
GL_ARRAY_BUFFER,
sizeof(bullet_vertices),
bullet_vertices,
GL_STATIC_DRAW
);
player.pos[0] = WIDTH / 2.0f;
player.pos[1] = HEIGHT / 2.0f;
player.pos[2] = 0.0;
player.left = FALSE;
player.right = FALSE;
player.up = FALSE;
player.space = FALSE;
mat4_translate(player.pos, player.mvp);
player.tex[0] = shader_load_texture("sprites/player.png");
player.tex[1] = shader_load_texture("sprites/bullet.png");
player.dx = 0.0f;
player.dy = 0.0f;
player.max = 8.0f;
player.bullet_speed = 6.0f;
player.num_ticks = 70;
for(i = 0; i WIDTH - 24.0f) {
player.bullets[i].pos[0] -= WIDTH;
draw_mirror = TRUE;
} else if(player.bullets[i].pos[0] <24.0f) {
player.bullets[i].pos[0] += WIDTH;
draw_mirror = TRUE;
}
if(player.bullets[i].pos[1] > HEIGHT - 24.0f) {
player.bullets[i].pos[1] -= HEIGHT;
draw_mirror = TRUE;
} else if(player.bullets[i].pos[1] <24.0f) {
player.bullets[i].pos[1] += HEIGHT;
draw_mirror = TRUE;
}
if(!draw_mirror) {
continue;
}
mat4_translate(player.bullets[i].pos, pos);
mat4_rotate_z(player.bullets[i].rot, rot);
mat4_multiply(pos, rot, player.mvp);
glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, player.mvp);
glDrawArrays(GL_TRIANGLES, 0, 6);
draw_mirror = FALSE;
}
// Draw Player Sprite
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, player.tex[0]);
glUniform1i(uniform_mytexture, 0);
mat4_translate(player.pos, pos);
mat4_rotate_z(player.rot, rot);
mat4_multiply(pos, rot, player.mvp);
glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, player.mvp);
glBindBuffer(GL_ARRAY_BUFFER, player.vbo[0]);
glVertexAttribPointer(
attribute_coord2d,
2,
GL_FLOAT,
GL_FALSE,
sizeof(float) * 4,
0
);
glVertexAttribPointer(
attribute_texcoord,
2,
GL_FLOAT,
GL_FALSE,
sizeof(float) * 4,
(void*)(sizeof(float) * 2)
);
glDrawArrays(GL_TRIANGLES, 0, 6);
if(player.pos[0] > WIDTH - 24.0f) {
player.pos[0] -= WIDTH;
draw_mirror = TRUE;
} else if(player.pos[0] <24.0f) {
player.pos[0] += WIDTH;
draw_mirror = TRUE;
}
if(player.pos[1] > HEIGHT - 24.0f) {
player.pos[1] -= HEIGHT;
draw_mirror = TRUE;
} else if(player.pos[1] <24.0f) {
player.pos[1] += HEIGHT;
draw_mirror = TRUE;
}
if(draw_mirror) {
draw_mirror = FALSE;
mat4_translate(player.pos, pos);
mat4_rotate_z(player.rot, rot);
mat4_multiply(pos, rot, player.mvp);
glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, player.mvp);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
// Draw Astroid Sprites
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, astroid.tex);
glUniform1i(uniform_mytexture, 0);
for(i = 0; i WIDTH - astroid.radius*scale[0]) {
astroid.rocks[i].pos[0] -= WIDTH;
draw_mirror = TRUE;
} else if(astroid.rocks[i].pos[0] HEIGHT - astroid.radius*scale[0]) {
astroid.rocks[i].pos[1] -= HEIGHT;
draw_mirror = TRUE;
} else if(astroid.rocks[i].pos[1] player.max) {
player.dx = player.max;
}
if(player.dy <-player.max) {
player.dy = -player.max;
} else if(player.dy > player.max) {
player.dy = player.max;
}
player.pos[0] += player.dx;
player.pos[1] += player.dy;
for(i = 0; i for(k = 0; k astroid.radius * scale) {
continue;
}
astroid.rocks[k].active = FALSE;
player.bullets[i].active = FALSE;
break;
}
}
for(i = 0; i keyval) {
case GDK_KEY_Left:
player.left = TRUE;
break;
case GDK_KEY_Right:
player.right = TRUE;
break;
case GDK_KEY_Up:
player.up = TRUE;
break;
case GDK_KEY_space:
if(!player.space) {
int i;
for(i = 0; i keyval) {
case GDK_KEY_Left:
player.left = FALSE;
break;
case GDK_KEY_Right:
player.right = FALSE;
break;
case GDK_KEY_Up:
player.up = FALSE;
break;
case GDK_KEY_space:
player.space = FALSE;
break;
}
}
Compile
$ gcc -c -o DashGL/dashgl.o DashGL/dashgl.c -lepoxy -lpng -lm
$ gcc `pkg-config --cflags gtk+-3.0` main.c DashGL/dashgl.o `pkg-config --libs gtk+-3.0` \
-lepoxy -lm -lpng
Run
$ ./a.out