Finally got sensors debugged

This commit is contained in:
Neale Pickett 2010-07-06 13:53:17 -06:00
parent 4720524639
commit 74b9e8e455
8 changed files with 520 additions and 226 deletions

View File

@ -1,6 +1,11 @@
LDFLAGS = -lm
all: test all: test
test: test-tanks test: test-tanks
./test-tanks ./test-tanks | m4 round.html.m4 - > round.html
test-tanks: test-tanks.o ctanks.o test-tanks: test-tanks.o ctanks.o
clean:
rm -f test-tanks *.o

197
ctanks.c
View File

@ -2,9 +2,22 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <math.h> #include <math.h>
#include "trig.h"
#include "ctanks.h" #include "ctanks.h"
/* Debugging help */
#define DUMPf(fmt, args...) fprintf(stderr, "%s:%s:%d " fmt "\n", __FILE__, __FUNCTION__, __LINE__, ##args)
#define DUMP() DUMPf("")
#define DUMP_d(v) DUMPf("%s = %d", #v, v)
#define DUMP_x(v) DUMPf("%s = 0x%x", #v, v)
#define DUMP_s(v) DUMPf("%s = %s", #v, v)
#define DUMP_c(v) DUMPf("%s = %c", #v, v)
#define DUMP_f(v) DUMPf("%s = %f", #v, v)
#define DUMP_xy(v) DUMPf("%s = (%f, %f)", #v, v[0], v[1]);
#define DUMP_angle(v) DUMPf("%s = %.3fπ", #v, (v/PI));
#define sq(x) ((x) * (x))
void void
tank_init(struct tank *tank, tank_run_func *run, void *udata) tank_init(struct tank *tank, tank_run_func *run, void *udata)
{ {
@ -32,16 +45,16 @@ tank_set_speed(struct tank *tank, float left, float right)
tank->speed.desired[1] = right; tank->speed.desired[1] = right;
} }
int float
tank_get_turret(struct tank *tank) tank_get_turret(struct tank *tank)
{ {
return tank->turret.current; return tank->turret.current;
} }
void void
tank_set_turret(struct tank *tank, int angle) tank_set_turret(struct tank *tank, float angle)
{ {
tank->turret.desired = angle; tank->turret.desired = fmodf(angle, 2*PI);
} }
int int
@ -50,7 +63,7 @@ tank_get_sensor(struct tank *tank, int sensor_num)
if ((sensor_num < 0) || (sensor_num > TANK_MAX_SENSORS)) { if ((sensor_num < 0) || (sensor_num > TANK_MAX_SENSORS)) {
return 0; return 0;
} }
return tank->sensor[sensor_num].triggered; return tank->sensors[sensor_num].triggered;
} }
void void
@ -60,16 +73,19 @@ tank_set_led(struct tank *tank, int active)
} }
static void static void
rotate_point(int angle, float point[2]) rotate_point(float angle, float point[2])
{ {
float cos_, sin_; float cos_, sin_;
float new[2]; float new[2];
cos_ = trig_cos(angle); cos_ = cosf(angle);
sin_ = trig_sin(angle); sin_ = sinf(angle);
new[0] = point[0]*cos_ + point[1]*sin_; new[0] = point[0]*cos_ - point[1]*sin_;
new[1] = point[0]*sin_ + point[1]*cos_; new[1] = point[0]*sin_ + point[1]*cos_;
point[0] = new[0];
point[1] = new[1];
} }
@ -95,7 +111,7 @@ tank_sensor_calc(struct tanks_game *game,
rpos[0] = tpos[0]; rpos[0] = tpos[0];
rpos[1] = tpos[1]; rpos[1] = tpos[1];
rotate_point(theta, rpos); rotate_point(-theta, rpos);
if (fabsf(rpos[1]) < TANK_RADIUS) { if (fabsf(rpos[1]) < TANK_RADIUS) {
that->killer = this; that->killer = this;
that->cause_death = "shot"; that->cause_death = "shot";
@ -103,50 +119,59 @@ tank_sensor_calc(struct tanks_game *game,
} }
/* Calculate sensors */ /* Calculate sensors */
for (i = 0; i < this->num_sensors; i += 1) { for (i = 0; i < TANK_MAX_SENSORS; i += 1) {
int theta; float theta;
float rpos[2]; float rpos[2];
float m_r, m_s; float m_r, m_s;
/* No need to re-check this sensor if it's already firing */ /* No need to re-check this sensor if it's already firing */
if (this->sensor[i].triggered) { if (this->sensors[i].triggered) {
continue; continue;
} }
/* If the tank is out of range, don't bother */ /* If the tank is out of range, don't bother */
if (dist2 < this->sensor[i].range_adj2) { if (dist2 > sq(this->sensors[i].range + TANK_RADIUS)) {
continue; continue;
} }
/* What is the angle of our sensor? */ /* What is the angle of our sensor? */
theta = this->angle; theta = this->angle + this->sensors[i].angle;
if (this->sensor[i].turret) { if (this->sensors[i].turret) {
theta += this->turret.current; theta += this->turret.current;
} }
theta = fmodf(theta, 2*PI);
/* Rotate tpos by theta */ /* Rotate tpos by theta */
rpos[0] = tpos[0]; rpos[0] = tpos[0];
rpos[1] = tpos[1]; rpos[1] = tpos[1];
rotate_point(theta, rpos); rotate_point(-theta, rpos);
/* Sensor is symmetrical, we can consider only first quadrant */ /* Sensor is symmetrical, we can consider only top quadrants */
rpos[1] = fabsf(rpos[1]); rpos[1] = fabsf(rpos[1]);
/* Compute slopes to tank and of our sensor */ /* Compute inverse slopes to tank and of our sensor */
m_s = tan(theta); m_s = 1 / tanf(this->sensors[i].width / 2);
m_r = rpos[1] / rpos[0]; m_r = rpos[0] / rpos[1];
/* If their slope is greater than ours, they're inside the arc */ if (1 == i) {
DUMP();
DUMP_angle(this->angle);
DUMP_angle(theta);
DUMP_xy(tpos);
DUMP_xy(rpos);
}
/* If our inverse slope is less than theirs, they're inside the arc */
if (m_r >= m_s) { if (m_r >= m_s) {
this->sensor[i].triggered = 1; this->sensors[i].triggered = 1;
continue; continue;
} }
/* Now check if the edge of the arc intersects the tank. Do this /* Now check if the edge of the arc intersects the tank. Do this
just like with firing. */ just like with firing. */
rotate_point(this->sensor[i].width / 2, rpos); rotate_point(this->sensors[i].width / -2, rpos);
if (fabsf(rpos[1]) < TANK_RADIUS) { if (fabsf(rpos[1]) < TANK_RADIUS) {
this->sensor[i].triggered = 1; this->sensors[i].triggered = 1;
} }
} }
} }
@ -157,11 +182,13 @@ do_shit_with(struct tanks_game *game,
struct tank *that) struct tank *that)
{ {
float vector[2]; float vector[2];
int dist2; /* Integer to avoid overflow! */ float dist2; /* distance squared */
float tpos; /* Translated position */ float tpos; /* Translated position */
int i; int i;
/* Don't bother if one is dead */ /* Don't bother if that is dead */
/* XXX: If three tanks occupy the same space at the same time, only
the first two will collide. */
if ((this->killer) || (that->killer)) { if ((this->killer) || (that->killer)) {
return; return;
} }
@ -171,16 +198,11 @@ do_shit_with(struct tanks_game *game,
for (i = 0; i < 2; i += 1) { for (i = 0; i < 2; i += 1) {
float halfsize = game->size[i] / 2; float halfsize = game->size[i] / 2;
/* XXX: is there a more elegant way to do this? */ vector[i] = halfsize - fabsf(that->position[i] - this->position[i] - halfsize);
vector[i] = that->position[i] - this->position[i];
if (2*vector[i] > game->size[i]) {
vector[i] -= game->size[i];
} else if (2*vector[i] < game->size[i]) {
vector[i] += game->size[i];
}
} }
/* Compute distance^2 for range comparisons */ /* Compute distance^2 for range comparisons */
dist2 = ((vector[0] * vector[0]) + (vector[1] * vector[1])); dist2 = sq(vector[0]) + sq(vector[1]);
/* If they're not within sensor range, there's nothing to do. */ /* If they're not within sensor range, there's nothing to do. */
if (dist2 > TANK_SENSOR_ADJ2) { if (dist2 > TANK_SENSOR_ADJ2) {
@ -193,7 +215,7 @@ do_shit_with(struct tanks_game *game,
this->cause_death = "collision"; this->cause_death = "collision";
that->killer = this; that->killer = this;
this->cause_death = "collision"; that->cause_death = "collision";
return; return;
} }
@ -203,43 +225,51 @@ do_shit_with(struct tanks_game *game,
tank_sensor_calc(game, that, this, dist2); tank_sensor_calc(game, that, this, dist2);
} }
void
tanks_print_tank(struct tanks_game *game,
struct tank *tank)
{
printf("%p\n", tank);
}
void void
tanks_move_tank(struct tanks_game *game, tanks_move_tank(struct tanks_game *game,
struct tank *tank) struct tank *tank)
{ {
int i; int i;
float movement[2]; float movement;
int angle; float angle;
/* Rotate the turret */
{
float rot_angle; /* Quickest way there */
/* Constrain rot_angle to between -PI and PI */
rot_angle = tank->turret.desired - tank->turret.current;
while (rot_angle < 0) {
rot_angle += 2*PI;
}
rot_angle = fmodf(PI + rot_angle, 2*PI) - PI;
rot_angle = min(TANK_MAX_TURRET_ROT, rot_angle);
rot_angle = max(-TANK_MAX_TURRET_ROT, rot_angle);
tank->turret.current = fmodf(tank->turret.current + rot_angle, 2*PI);
}
/* Fakey acceleration */ /* Fakey acceleration */
for (i = 0; i < 2; i += 1) { for (i = 0; i < 2; i += 1) {
if (tank->speed.current[i] == tank->speed.desired[i]) { if (tank->speed.current[i] == tank->speed.desired[i]) {
/* Do nothing */ /* Do nothing */
} else if (tank->speed.current[i] < tank->speed.desired[i]) { } else if (tank->speed.current[i] < tank->speed.desired[i]) {
tank->speed.current[i] = max(tank->speed.current[i] - TANK_MAX_ACCEL, tank->speed.current[i] = min(tank->speed.current[i] + TANK_MAX_ACCEL,
tank->speed.desired[i]); tank->speed.desired[i]);
} else { } else {
tank->speed.current[i] = min(tank->speed.current[i] + TANK_MAX_ACCEL, tank->speed.current[i] = max(tank->speed.current[i] - TANK_MAX_ACCEL,
tank->speed.desired[i]); tank->speed.desired[i]);
} }
} }
/* The simple case */ /* The simple case */
if (tank->speed.current[0] == tank->speed.current[1]) { if (tank->speed.current[0] == tank->speed.current[1]) {
movement[0] = tank->speed.current[0]; movement = tank->speed.current[0] * (TANK_TOP_SPEED / 100.0);
movement[1] = tank->speed.current[1]; angle = 0;
angle = tank->angle;
} else { } else {
/* pflarr's original comment: /* pflarr's original comment:
* *
* The tank drives around in a circle of radius r, which is some * * The tank drives around in a circle of radius r, which is some
* offset on a line perpendicular to the tank. The distance it * offset on a line perpendicular to the tank. The distance it
* travels around the circle varies with the speed of each tread, * travels around the circle varies with the speed of each tread,
* and is such that each side of the tank moves an equal angle * and is such that each side of the tank moves an equal angle
@ -250,29 +280,25 @@ tanks_move_tank(struct tanks_game *game,
float friction; float friction;
float v[2]; float v[2];
float So, Si; float So, Si;
float w, r; float r;
int theta; float theta;
int dir; int dir;
/* The first thing Paul's code does is find "friction", which seems /* The first thing Paul's code does is find "friction", which seems
to be a penalty for having the treads go in opposite directions. to be a penalty for having the treads go in opposite directions.
This probably plays hell with precisely-planned tanks, which I This probably plays hell with precisely-planned tanks, which I
find very ha ha. */ find very ha ha. */
friction = .25 * (fabsf(tank->speed.current[0] - tank->speed.current[1]) / 200); friction = .75 * (fabsf(tank->speed.current[0] - tank->speed.current[1]) / 200);
v[0] = tank->speed.current[0] * (1 - friction) * (TANK_TOP_SPEED / 100.0);
v[0] = tank->speed.current[0] * friction; v[1] = tank->speed.current[1] * (1 - friction) * (TANK_TOP_SPEED / 100.0);
v[1] = tank->speed.current[1] * friction;
/* Outside and inside speeds */ /* Outside and inside speeds */
So = max(v[0], v[1]); So = max(v[0], v[1]);
Si = min(v[0], v[1]); Si = min(v[0], v[1]);
dir = (v[0] > v[1]) ? 1 : -1; dir = (v[0] > v[1]) ? 1 : -1;
/* Width of tank */
w = TANK_RADIUS * 2;
/* Radius of circle to outside tread (use similar triangles) */ /* Radius of circle to outside tread (use similar triangles) */
r = So * w / (So - Si); r = So * (TANK_RADIUS * 2) / (So - Si);
/* pflarr: /* pflarr:
@ -285,28 +311,25 @@ tanks_move_tank(struct tanks_game *game,
theta = So/r theta = So/r
We multiply it by dir to adjust for the direction of rotation We multiply it by dir to adjust for the direction of rotation
*/ */
theta = rad2deg(So/r) * dir; theta = So/r * dir;
/* Translate so the circle's center is 0,0, rotate the point by movement = r * tanf(theta);
theta, then add back in. */
v[0] = trig_cos(tank->angle + 90*dir) * (TANK_RADIUS - r);
v[1] = trig_sin(tank->angle + 90*dir) * (TANK_RADIUS - r);
movement[0] = v[0];
movement[1] = v[1];
rotate_point(theta, movement);
movement[0] -= v[0];
movement[1] -= v[1];
angle = theta; angle = theta;
} }
/* Now move the tank */ /* Now move the tank */
tank->angle = fmodf(tank->angle + angle + 2*PI, 2*PI);
{
float m[2];
m[0] = cosf(tank->angle) * movement;
m[1] = sinf(tank->angle) * movement;
for (i = 0; i < 2; i += 1) { for (i = 0; i < 2; i += 1) {
tank->position[i] = fmodf(tank->position[i] + movement[i] + game->size[i], tank->position[i] = fmodf(tank->position[i] + m[i] + game->size[i],
game->size[i]); game->size[i]);
} }
tank->angle = (tank->angle + angle + 360) % 360; }
} }
void void
@ -314,11 +337,31 @@ tanks_run_turn(struct tanks_game *game, struct tank *tanks, int ntanks)
{ {
int i, j; int i, j;
/* Run programs */
for (i = 0; i < ntanks; i += 1) {
if (! tanks[i].killer) {
tanks[i].run(&tanks[i], &tanks[i].udata);
}
}
/* Clear sensors */
for (i = 0; i < ntanks; i += 1) {
for (j = 0; j < TANK_MAX_SENSORS; j += 1) {
tanks[i].sensors[j].triggered = 0;
}
}
/* Move */
for (i = 0; i < ntanks; i += 1) {
if (! tanks[i].killer) {
tanks_move_tank(game, &(tanks[i]));
}
}
/* Sense and fire */
for (i = 0; i < ntanks; i += 1) { for (i = 0; i < ntanks; i += 1) {
for (j = i + 1; j < ntanks; j += 1) { for (j = i + 1; j < ntanks; j += 1) {
do_shit_with(game, &(tanks[i]), &(tanks[j])); do_shit_with(game, &(tanks[i]), &(tanks[j]));
} }
tanks_print_tank(game, &(tanks[i]));
tanks_move_tank(game, &(tanks[i]));
} }
} }

View File

@ -2,11 +2,15 @@
#define __CTANKS_H__ #define __CTANKS_H__
/* Some useful constants */ /* Some useful constants */
#define PI 3.14159265358979323846
#define TANK_MAX_SENSORS 10 #define TANK_MAX_SENSORS 10
#define TANK_RADIUS 7.5 #define TANK_RADIUS 7.5
#define TANK_SENSOR_RANGE 100 #define TANK_SENSOR_RANGE 100
#define TANK_CANNON_RANGE (TANK_SENSOR_RANGE / 2) #define TANK_CANNON_RANGE (TANK_SENSOR_RANGE / 2)
#define TANK_MAX_ACCEL 35 #define TANK_MAX_ACCEL 35
#define TANK_MAX_TURRET_ROT (PI/3)
#define TANK_TOP_SPEED 7
/* (tank radius + tank radius)^2 */ /* (tank radius + tank radius)^2 */
#define TANK_COLLISION_ADJ2 \ #define TANK_COLLISION_ADJ2 \
@ -18,6 +22,16 @@
#define TANK_SENSOR_ADJ2 \ #define TANK_SENSOR_ADJ2 \
((TANK_SENSOR_RANGE + TANK_RADIUS) * (TANK_SENSOR_RANGE + TANK_RADIUS)) ((TANK_SENSOR_RANGE + TANK_RADIUS) * (TANK_SENSOR_RANGE + TANK_RADIUS))
#ifndef rad2deg
#define rad2deg(r) ((int)(180*(r)/PI))
#endif
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
struct tanks_game { struct tanks_game {
float size[2]; /* dimensions of playing field */ float size[2]; /* dimensions of playing field */
}; };
@ -25,10 +39,10 @@ struct tanks_game {
struct tank; struct tank;
struct sensor { struct sensor {
int angle; float angle;
int width; float width;
float range; int range;
float range_adj2; /* (range + TANK_RADIUS)^2 */ int range_adj2; /* (range + TANK_RADIUS)^2 */
int turret; /* Mounted to turret? */ int turret; /* Mounted to turret? */
int triggered; int triggered;
}; };
@ -37,19 +51,18 @@ typedef void tank_run_func(struct tank *, void *);
struct tank { struct tank {
float position[2]; /* Current position on the board */ float position[2]; /* Current position on the board */
int angle; /* Current orientation */ float angle; /* Current orientation */
struct { struct {
float current[2]; /* Current tread speed */ float current[2]; /* Current tread speed */
float desired[2]; /* Desired tread speed */ float desired[2]; /* Desired tread speed */
} speed; } speed;
struct { struct {
int current; /* Current turret angle */ float current; /* Current turret angle */
int desired; /* Desired turret angle */ float desired; /* Desired turret angle */
int firing; /* True if firing this turn */ int firing; /* True if firing this turn */
int recharge; /* Turns until gun is recharged */ int recharge; /* Turns until gun is recharged */
} turret; } turret;
struct sensor sensor[TANK_MAX_SENSORS]; /* Sensor array */ struct sensor sensors[TANK_MAX_SENSORS]; /* Sensor array */
int num_sensors; /* Number of sensors */
int led; /* State of the LED */ int led; /* State of the LED */
struct tank *killer; /* Killer, or NULL if alive */ struct tank *killer; /* Killer, or NULL if alive */
char *cause_death; /* Cause of death */ char *cause_death; /* Cause of death */
@ -76,10 +89,10 @@ void tank_fire(struct tank *tank);
void tank_set_speed(struct tank *tank, float left, float right); void tank_set_speed(struct tank *tank, float left, float right);
/** Get the current turret angle */ /** Get the current turret angle */
int tank_get_turret(struct tank *tank); float tank_get_turret(struct tank *tank);
/** Set the desired turret angle */ /** Set the desired turret angle */
void tank_set_turret(struct tank *tank, int angle); void tank_set_turret(struct tank *tank, float angle);
/** Is a sensor active? */ /** Is a sensor active? */
int tank_get_sensor(struct tank *tank, int sensor_num); int tank_get_sensor(struct tank *tank, int sensor_num);

28
round.html.m4 Normal file
View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<title>Tank Game</title>
<script type="application/javascript" src="tanks.js"></script>
<style type="text/css">
body {
background-color: #444444;
color: white;
}
</style>
<script type="application/javascript">
function go() {
start(
// Start JSON data
divert(1)
// end JSON data
);
}
window.onload = go;
</script>
</head>
<body>
<div id="game_box"><canvas id="battlefield"></canvas></div>
<p><span id="fps">0</span> fps</p>
</body>
</html>
divert(0)

219
tanks.js Normal file
View File

@ -0,0 +1,219 @@
function dbg(o) {
e = document.getElementById("debug");
e.innerHTML = o;
}
function torgba(color, alpha) {
var r = parseInt(color.substring(1,3), 16);
var g = parseInt(color.substring(3,5), 16);
var b = parseInt(color.substring(5,7), 16);
return "rgba(" + r + "," + g + "," + b + "," + alpha + ")";
}
function Tank(ctx, width, height, color, sensors) {
var craterStroke = torgba(color, 0.5);
var craterFill = torgba(color, 0.2);
var sensorStroke = torgba(color, 0.4);
var maxlen = 0;
this.x = 0;
this.y = 0;
this.rotation = 0;
this.turret = 0;
// Do all the yucky math up front
this.sensors = new Array();
for (i in sensors) {
var s = sensors[i];
// r, angle, width, turret
this.sensors[i] = new Array();
this.sensors[i][0] = s[0];
this.sensors[i][1] = s[1] - s[2]/2;
this.sensors[i][2] = s[1] + s[2]/2;
this.sensors[i][3] = s[3]?1:0;
if (s[0] > maxlen) {
maxlen = s[0];
}
}
// Set up our state, for later interleaved draw requests
this.set_state = function(x, y, rotation, turret, flags, sensor_state) {
this.x = x;
this.y = y;
this.rotation = rotation;
this.turret = turret;
if (flags & 1) {
this.fire = 5;
}
this.led = flags & 2;
this.sensor_state = sensor_state;
}
this.draw_crater = function() {
var points = 7;
var angle = Math.PI / points;
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.rotation);
ctx.lineWidth = 2;
ctx.strokeStyle = craterStroke;
ctx.fillStyle = craterFill;
ctx.beginPath();
ctx.moveTo(12, 0);
for (i = 0; i < points; i += 1) {
ctx.rotate(angle);
ctx.lineTo(6, 0);
ctx.rotate(angle);
ctx.lineTo(12, 0);
}
ctx.closePath()
ctx.stroke();
ctx.fill();
ctx.restore();
}
this.draw_sensors = function() {
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.rotation);
ctx.lineWidth = 1;
for (i in this.sensors) {
var s = this.sensors[i];
var adj = this.turret * s[3];
if (this.sensor_state & (1 << i)) {
// Sensor is triggered
ctx.strokeStyle = "#000";
} else {
ctx.strokeStyle = sensorStroke;
}
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.arc(0, 0, s[0], s[1] + adj, s[2] + adj, false);
ctx.closePath();
ctx.stroke();
}
ctx.restore();
}
this.draw_tank = function() {
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.rotation);
ctx.fillStyle = color;
ctx.fillRect(-5, -4, 10, 8);
ctx.fillStyle = "#777";
ctx.fillRect(-7, -9, 15, 5);
ctx.fillRect(-7, 4, 15, 5);
ctx.rotate(this.turret);
if (this.fire) {
ctx.fillStyle = ("rgba(68,204,68," + this.fire/5 +")");
ctx.fillRect(0, -1, 45, 2);
this.fire -= 1;
} else {
if (this.led) {
ctx.fillStyle = "#f00";
} else {
ctx.fillStyle = "#000";
}
ctx.fillRect(0, -1, 10, 2);
}
ctx.restore();
}
this.draw_wrap_sensors = function() {
var orig_x = this.x;
var orig_y = this.y;
for (x = this.x - width; x < width + maxlen; x += width) {
for (y = this.y - height; y < height + maxlen; y += height) {
if ((-maxlen < x) && (x < width + maxlen) &&
(-maxlen < y) && (y < height + maxlen)) {
this.x = x;
this.y = y;
this.draw_sensors();
}
}
}
this.x = orig_x;
this.y = orig_y;
}
}
function start(game) {
var canvas = document.getElementById('battlefield');
var ctx = canvas.getContext('2d');
var loop_id;
canvas.width = game[0][0];
canvas.height = game[0][1];
// game[2] is tank descriptions
var turns = game[2];
// Set up tanks
var tanks = new Array();
for (i in game[1]) {
var desc = game[1][i];
tanks[i] = new Tank(ctx, game[0][0], game[0][1], desc[0], desc[1]);
}
var frame = 0;
var lastframe = 0;
var fps = document.getElementById('fps');
function update_fps() {
fps.innerHTML = (frame - lastframe);
lastframe = frame;
}
function update() {
var idx = frame % (turns.length + 20);
var turn;
frame += 1;
if (idx >= turns.length) {
return;
}
canvas.width = canvas.width;
turn = turns[idx];
// Draw craters first
for (i in turn) {
t = turn[i];
if (! t) {
tanks[i].draw_crater();
}
}
// Then sensors
for (i in turn) {
t = turn[i];
if (t) {
// Surely there's a better way to do this.
tanks[i].set_state(t[0], t[1], t[2], t[3], t[4], t[5]);
tanks[i].draw_wrap_sensors();
}
}
// Then tanks
for (i in turn) {
t = turn[i];
if (t) {
tanks[i].draw_tank()
}
}
}
//loop_id = setInterval(update, 66);
loop_id = setInterval(update, 200);
if (fps) {
setInterval(update_fps, 1000);
}
}

View File

@ -2,24 +2,128 @@
#include <math.h> #include <math.h>
#include "ctanks.h" #include "ctanks.h"
#define NTANKS 2
void void
test_run(struct tank *tank, void *unused) test_run(struct tank *tank, void *unused)
{ {
tank_set_speed(tank, 30, 50); tank_set_speed(tank, 61, 60);
tank_set_turret(tank, fmod(tank->turret.desired + 0.2, 2*PI)); tank_set_turret(tank, 0);
}
void
sitting_duck(struct tank *tank, void *unused)
{
tank_set_turret(tank, tank->turret.desired + PI/15);
} }
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
struct tank mytank; struct tanks_game game;
struct tank mytanks[NTANKS];
int i; int i;
tank_init(&mytank, test_run, NULL); game.size[0] = 600;
printf("hi\n"); game.size[1] = 600;
for (i = 0; i < 4; i += 1) {
printf("%f\n", mytank.turret.desired); printf("[\n");
mytank.run(&mytank, mytank.udata); printf("[%d, %d, %d],\n",
(int)game.size[0], (int)game.size[1], TANK_CANNON_RANGE);
printf("[\n");
for (i = 0; i < NTANKS; i += 1) {
if (i == 1) {
printf(" [\"#888888\",[");
tank_init(&mytanks[i], sitting_duck, NULL);
} else {
int j;
printf(" [\"#ff4444\",[");
tank_init(&mytanks[i], test_run, NULL);
mytanks[i].sensors[0].angle = 0;
mytanks[i].sensors[0].width = PI/10;
mytanks[i].sensors[0].range = 50;
mytanks[i].sensors[0].turret = 1;
mytanks[i].sensors[1].angle = 0*PI/2;
mytanks[i].sensors[1].width = PI/3;
mytanks[i].sensors[1].range = 100;
mytanks[i].sensors[1].turret = 1;
mytanks[i].sensors[2].angle = 1*PI/2;
mytanks[i].sensors[2].width = PI/3;
mytanks[i].sensors[2].range = 100;
mytanks[i].sensors[2].turret = 1;
mytanks[i].sensors[3].angle = 2*PI/2;
mytanks[i].sensors[3].width = PI/3;
mytanks[i].sensors[3].range = 100;
mytanks[i].sensors[3].turret = 1;
mytanks[i].sensors[4].angle = 3*PI/2;
mytanks[i].sensors[4].width = PI/3;
mytanks[i].sensors[4].range = 100;
mytanks[i].sensors[4].turret = 1;
for (j = 0; j < TANK_MAX_SENSORS; j += 1) {
struct sensor *s = &(mytanks[i].sensors[j]);
if (s->range) {
printf("[%d, %.2f, %.2f, %d],",
(int)(s->range),
s->angle,
s->width,
s->turret);
} }
}
}
mytanks[i].position[0] = (game.size[0] / NTANKS) * i + 50;
mytanks[i].position[1] = 50;
/* XXX: print sensors */
printf("]],\n");
}
printf("],\n");
printf("// Rounds\n");
printf("[\n");
for (i = 0; i < 200; i += 1) {
int j;
tanks_run_turn(&game, mytanks, NTANKS);
printf("[\n");
for (j = 0; j < NTANKS; j += 1) {
struct tank *t = &(mytanks[j]);
if (t->killer) {
printf(" 0,\n");
} else {
int k;
int flags = 0;
int sensors = 0;
for (k = 0; k < TANK_MAX_SENSORS; k += 1) {
if (t->sensors[k].triggered) {
sensors |= (1 << k);
}
}
if (t->turret.firing) {
flags |= 1;
}
if (t->led) {
flags |= 2;
}
printf(" [%d,%d,%.2f,%.2f,%d,%d],\n",
(int)(t->position[0]),
(int)(t->position[1]),
t->angle,
t->turret.current,
flags,
sensors);
}
}
printf("],\n");
}
printf("]]\n");
return 0; return 0;
} }

93
trig.c
View File

@ -1,93 +0,0 @@
#include <stdlib.h>
#include <math.h>
#include "trig.h"
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
static float trig_cos_table[] = {
1.000000, 0.999848, 0.999391, 0.998630, 0.997564, 0.996195,
0.994522, 0.992546, 0.990268, 0.987688, 0.984808, 0.981627,
0.978148, 0.974370, 0.970296, 0.965926, 0.961262, 0.956305,
0.951057, 0.945519, 0.939693, 0.933580, 0.927184, 0.920505,
0.913545, 0.906308, 0.898794, 0.891007, 0.882948, 0.874620,
0.866025, 0.857167, 0.848048, 0.838671, 0.829038, 0.819152,
0.809017, 0.798636, 0.788011, 0.777146, 0.766044, 0.754710,
0.743145, 0.731354, 0.719340, 0.707107, 0.694658, 0.681998,
0.669131, 0.656059, 0.642788, 0.629320, 0.615661, 0.601815,
0.587785, 0.573576, 0.559193, 0.544639, 0.529919, 0.515038,
0.500000, 0.484810, 0.469472, 0.453990, 0.438371, 0.422618,
0.406737, 0.390731, 0.374607, 0.358368, 0.342020, 0.325568,
0.309017, 0.292372, 0.275637, 0.258819, 0.241922, 0.224951,
0.207912, 0.190809, 0.173648, 0.156434, 0.139173, 0.121869,
0.104528, 0.087156, 0.069756, 0.052336, 0.034899, 0.017452,
0.000000,
};
float
trig_cos(int angle)
{
int a;
float ret;
a = abs(angle) % 180;
if (a > 90) {
a = 180 - a;
}
ret = trig_cos_table[a];
a = abs(angle) % 360;
if ((a > 90) && (a < 270)) {
ret = -ret;
}
return ret;
}
float
trig_sin(int angle)
{
return trig_cos(90 - angle);
}
float
trig_tan(int angle)
{
return trig_sin(angle) / trig_cos(angle);
}
int
trig_asin(float x)
{
return rad2deg(asinf(x));
}
int
trig_acos(float x)
{
return rad2deg(acosf(x));
}
int
trig_atan2(float y, float x)
{
return rad2deg(atan2f(y, x));
}
#if 0
#include <stdio.h>
int
main()
{
int i, j;
float f;
int t;
for (i = 0; i < 600; i += 1) {
printf("%-04d %-0.6f %-0.6f\n", i, trig_cos(i), cosf(deg2rad(i)));
}
return 0;
}
#endif

25
trig.h
View File

@ -1,25 +0,0 @@
#ifndef __TRIG_H__
#define __TRIG_H__
/** Trigonometry in degrees
*
* It's just a library to do discrete(-ish) trig, using degrees. It
* uses a lookup table to make sin, cos, and tan really fast.
* Everything is as slow as normal :)
*/
/* Just to make it clear what scale these functions are dealing with */
#define PI 3.14159265358979323846
#define rad2deg(rad) ((int)(rad * 180 / PI))
#define deg2rad(deg) ((float)(deg * PI / 180))
float trig_cos(int angle);
float trig_sin(int angle);
float trig_atan(int angle);
int trig_acos(float angle);
int trig_asin(float angle);
int trig_atan2(float y, float x);
#endif /* __TRIG_H__ */