mirror of https://github.com/dirtbags/tanks.git
Finally got sensors debugged
This commit is contained in:
parent
4720524639
commit
74b9e8e455
7
Makefile
7
Makefile
|
@ -1,6 +1,11 @@
|
|||
LDFLAGS = -lm
|
||||
|
||||
all: test
|
||||
|
||||
test: test-tanks
|
||||
./test-tanks
|
||||
./test-tanks | m4 round.html.m4 - > round.html
|
||||
|
||||
test-tanks: test-tanks.o ctanks.o
|
||||
|
||||
clean:
|
||||
rm -f test-tanks *.o
|
207
ctanks.c
207
ctanks.c
|
@ -2,9 +2,22 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "trig.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
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
float
|
||||
tank_get_turret(struct tank *tank)
|
||||
{
|
||||
return tank->turret.current;
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -50,7 +63,7 @@ tank_get_sensor(struct tank *tank, int sensor_num)
|
|||
if ((sensor_num < 0) || (sensor_num > TANK_MAX_SENSORS)) {
|
||||
return 0;
|
||||
}
|
||||
return tank->sensor[sensor_num].triggered;
|
||||
return tank->sensors[sensor_num].triggered;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -60,16 +73,19 @@ tank_set_led(struct tank *tank, int active)
|
|||
}
|
||||
|
||||
static void
|
||||
rotate_point(int angle, float point[2])
|
||||
rotate_point(float angle, float point[2])
|
||||
{
|
||||
float cos_, sin_;
|
||||
float new[2];
|
||||
|
||||
cos_ = trig_cos(angle);
|
||||
sin_ = trig_sin(angle);
|
||||
cos_ = cosf(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_;
|
||||
|
||||
point[0] = new[0];
|
||||
point[1] = new[1];
|
||||
}
|
||||
|
||||
|
||||
|
@ -95,7 +111,7 @@ tank_sensor_calc(struct tanks_game *game,
|
|||
|
||||
rpos[0] = tpos[0];
|
||||
rpos[1] = tpos[1];
|
||||
rotate_point(theta, rpos);
|
||||
rotate_point(-theta, rpos);
|
||||
if (fabsf(rpos[1]) < TANK_RADIUS) {
|
||||
that->killer = this;
|
||||
that->cause_death = "shot";
|
||||
|
@ -103,50 +119,59 @@ tank_sensor_calc(struct tanks_game *game,
|
|||
}
|
||||
|
||||
/* Calculate sensors */
|
||||
for (i = 0; i < this->num_sensors; i += 1) {
|
||||
int theta;
|
||||
for (i = 0; i < TANK_MAX_SENSORS; i += 1) {
|
||||
float theta;
|
||||
float rpos[2];
|
||||
float m_r, m_s;
|
||||
|
||||
/* No need to re-check this sensor if it's already firing */
|
||||
if (this->sensor[i].triggered) {
|
||||
if (this->sensors[i].triggered) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* What is the angle of our sensor? */
|
||||
theta = this->angle;
|
||||
if (this->sensor[i].turret) {
|
||||
theta = this->angle + this->sensors[i].angle;
|
||||
if (this->sensors[i].turret) {
|
||||
theta += this->turret.current;
|
||||
}
|
||||
theta = fmodf(theta, 2*PI);
|
||||
|
||||
/* Rotate tpos by theta */
|
||||
rpos[0] = tpos[0];
|
||||
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]);
|
||||
|
||||
/* Compute slopes to tank and of our sensor */
|
||||
m_s = tan(theta);
|
||||
m_r = rpos[1] / rpos[0];
|
||||
/* Compute inverse slopes to tank and of our sensor */
|
||||
m_s = 1 / tanf(this->sensors[i].width / 2);
|
||||
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) {
|
||||
this->sensor[i].triggered = 1;
|
||||
this->sensors[i].triggered = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Now check if the edge of the arc intersects the tank. Do this
|
||||
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) {
|
||||
this->sensor[i].triggered = 1;
|
||||
this->sensors[i].triggered = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -156,12 +181,14 @@ do_shit_with(struct tanks_game *game,
|
|||
struct tank *this,
|
||||
struct tank *that)
|
||||
{
|
||||
float vector[2];
|
||||
int dist2; /* Integer to avoid overflow! */
|
||||
float tpos; /* Translated position */
|
||||
int i;
|
||||
float vector[2];
|
||||
float dist2; /* distance squared */
|
||||
float tpos; /* Translated position */
|
||||
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)) {
|
||||
return;
|
||||
}
|
||||
|
@ -171,16 +198,11 @@ do_shit_with(struct tanks_game *game,
|
|||
for (i = 0; i < 2; i += 1) {
|
||||
float halfsize = game->size[i] / 2;
|
||||
|
||||
/* XXX: is there a more elegant way to do this? */
|
||||
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];
|
||||
}
|
||||
vector[i] = halfsize - fabsf(that->position[i] - this->position[i] - halfsize);
|
||||
}
|
||||
|
||||
/* 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 (dist2 > TANK_SENSOR_ADJ2) {
|
||||
|
@ -193,7 +215,7 @@ do_shit_with(struct tanks_game *game,
|
|||
this->cause_death = "collision";
|
||||
|
||||
that->killer = this;
|
||||
this->cause_death = "collision";
|
||||
that->cause_death = "collision";
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -203,43 +225,51 @@ do_shit_with(struct tanks_game *game,
|
|||
tank_sensor_calc(game, that, this, dist2);
|
||||
}
|
||||
|
||||
void
|
||||
tanks_print_tank(struct tanks_game *game,
|
||||
struct tank *tank)
|
||||
{
|
||||
printf("%p\n", tank);
|
||||
}
|
||||
|
||||
void
|
||||
tanks_move_tank(struct tanks_game *game,
|
||||
struct tank *tank)
|
||||
{
|
||||
int i;
|
||||
float movement[2];
|
||||
int angle;
|
||||
float movement;
|
||||
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 */
|
||||
for (i = 0; i < 2; i += 1) {
|
||||
if (tank->speed.current[i] == tank->speed.desired[i]) {
|
||||
/* Do nothing */
|
||||
} 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]);
|
||||
} 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]);
|
||||
}
|
||||
}
|
||||
|
||||
/* The simple case */
|
||||
if (tank->speed.current[0] == tank->speed.current[1]) {
|
||||
movement[0] = tank->speed.current[0];
|
||||
movement[1] = tank->speed.current[1];
|
||||
angle = tank->angle;
|
||||
movement = tank->speed.current[0] * (TANK_TOP_SPEED / 100.0);
|
||||
angle = 0;
|
||||
} else {
|
||||
/* 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
|
||||
* travels around the circle varies with the speed of each tread,
|
||||
* 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 v[2];
|
||||
float So, Si;
|
||||
float w, r;
|
||||
int theta;
|
||||
float r;
|
||||
float theta;
|
||||
int dir;
|
||||
|
||||
/* The first thing Paul's code does is find "friction", which seems
|
||||
to be a penalty for having the treads go in opposite directions.
|
||||
This probably plays hell with precisely-planned tanks, which I
|
||||
find very ha ha. */
|
||||
friction = .25 * (fabsf(tank->speed.current[0] - tank->speed.current[1]) / 200);
|
||||
|
||||
v[0] = tank->speed.current[0] * friction;
|
||||
v[1] = tank->speed.current[1] * friction;
|
||||
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[1] = tank->speed.current[1] * (1 - friction) * (TANK_TOP_SPEED / 100.0);
|
||||
|
||||
/* Outside and inside speeds */
|
||||
So = max(v[0], v[1]);
|
||||
Si = min(v[0], v[1]);
|
||||
dir = (v[0] > v[1]) ? 1 : -1;
|
||||
|
||||
/* Width of tank */
|
||||
w = TANK_RADIUS * 2;
|
||||
|
||||
/* Radius of circle to outside tread (use similar triangles) */
|
||||
r = So * w / (So - Si);
|
||||
r = So * (TANK_RADIUS * 2) / (So - Si);
|
||||
|
||||
/* pflarr:
|
||||
|
||||
|
@ -285,28 +311,25 @@ tanks_move_tank(struct tanks_game *game,
|
|||
theta = So/r
|
||||
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
|
||||
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];
|
||||
movement = r * tanf(theta);
|
||||
angle = theta;
|
||||
}
|
||||
|
||||
/* Now move the tank */
|
||||
for (i = 0; i < 2; i += 1) {
|
||||
tank->position[i] = fmodf(tank->position[i] + movement[i] + game->size[i],
|
||||
game->size[i]);
|
||||
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) {
|
||||
tank->position[i] = fmodf(tank->position[i] + m[i] + game->size[i],
|
||||
game->size[i]);
|
||||
}
|
||||
}
|
||||
tank->angle = (tank->angle + angle + 360) % 360;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -314,11 +337,31 @@ tanks_run_turn(struct tanks_game *game, struct tank *tanks, int ntanks)
|
|||
{
|
||||
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 (j = i + 1; j < ntanks; j += 1) {
|
||||
do_shit_with(game, &(tanks[i]), &(tanks[j]));
|
||||
}
|
||||
tanks_print_tank(game, &(tanks[i]));
|
||||
tanks_move_tank(game, &(tanks[i]));
|
||||
}
|
||||
}
|
||||
|
|
45
ctanks.h
45
ctanks.h
|
@ -2,11 +2,15 @@
|
|||
#define __CTANKS_H__
|
||||
|
||||
/* Some useful constants */
|
||||
#define TANK_MAX_SENSORS 10
|
||||
#define TANK_RADIUS 7.5
|
||||
#define TANK_SENSOR_RANGE 100
|
||||
#define TANK_CANNON_RANGE (TANK_SENSOR_RANGE / 2)
|
||||
#define TANK_MAX_ACCEL 35
|
||||
#define PI 3.14159265358979323846
|
||||
|
||||
#define TANK_MAX_SENSORS 10
|
||||
#define TANK_RADIUS 7.5
|
||||
#define TANK_SENSOR_RANGE 100
|
||||
#define TANK_CANNON_RANGE (TANK_SENSOR_RANGE / 2)
|
||||
#define TANK_MAX_ACCEL 35
|
||||
#define TANK_MAX_TURRET_ROT (PI/3)
|
||||
#define TANK_TOP_SPEED 7
|
||||
|
||||
/* (tank radius + tank radius)^2 */
|
||||
#define TANK_COLLISION_ADJ2 \
|
||||
|
@ -18,6 +22,16 @@
|
|||
#define TANK_SENSOR_ADJ2 \
|
||||
((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 {
|
||||
float size[2]; /* dimensions of playing field */
|
||||
};
|
||||
|
@ -25,10 +39,10 @@ struct tanks_game {
|
|||
struct tank;
|
||||
|
||||
struct sensor {
|
||||
int angle;
|
||||
int width;
|
||||
float range;
|
||||
float range_adj2; /* (range + TANK_RADIUS)^2 */
|
||||
float angle;
|
||||
float width;
|
||||
int range;
|
||||
int range_adj2; /* (range + TANK_RADIUS)^2 */
|
||||
int turret; /* Mounted to turret? */
|
||||
int triggered;
|
||||
};
|
||||
|
@ -37,19 +51,18 @@ typedef void tank_run_func(struct tank *, void *);
|
|||
|
||||
struct tank {
|
||||
float position[2]; /* Current position on the board */
|
||||
int angle; /* Current orientation */
|
||||
float angle; /* Current orientation */
|
||||
struct {
|
||||
float current[2]; /* Current tread speed */
|
||||
float desired[2]; /* Desired tread speed */
|
||||
} speed;
|
||||
struct {
|
||||
int current; /* Current turret angle */
|
||||
int desired; /* Desired turret angle */
|
||||
float current; /* Current turret angle */
|
||||
float desired; /* Desired turret angle */
|
||||
int firing; /* True if firing this turn */
|
||||
int recharge; /* Turns until gun is recharged */
|
||||
} turret;
|
||||
struct sensor sensor[TANK_MAX_SENSORS]; /* Sensor array */
|
||||
int num_sensors; /* Number of sensors */
|
||||
struct sensor sensors[TANK_MAX_SENSORS]; /* Sensor array */
|
||||
int led; /* State of the LED */
|
||||
struct tank *killer; /* Killer, or NULL if alive */
|
||||
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);
|
||||
|
||||
/** Get the current turret angle */
|
||||
int tank_get_turret(struct tank *tank);
|
||||
float tank_get_turret(struct tank *tank);
|
||||
|
||||
/** 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? */
|
||||
int tank_get_sensor(struct tank *tank, int sensor_num);
|
||||
|
|
|
@ -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)
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
122
test-tanks.c
122
test-tanks.c
|
@ -2,24 +2,128 @@
|
|||
#include <math.h>
|
||||
#include "ctanks.h"
|
||||
|
||||
#define NTANKS 2
|
||||
|
||||
void
|
||||
test_run(struct tank *tank, void *unused)
|
||||
{
|
||||
tank_set_speed(tank, 30, 50);
|
||||
tank_set_turret(tank, fmod(tank->turret.desired + 0.2, 2*PI));
|
||||
tank_set_speed(tank, 61, 60);
|
||||
tank_set_turret(tank, 0);
|
||||
}
|
||||
|
||||
void
|
||||
sitting_duck(struct tank *tank, void *unused)
|
||||
{
|
||||
tank_set_turret(tank, tank->turret.desired + PI/15);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct tank mytank;
|
||||
int i;
|
||||
struct tanks_game game;
|
||||
struct tank mytanks[NTANKS];
|
||||
int i;
|
||||
|
||||
tank_init(&mytank, test_run, NULL);
|
||||
printf("hi\n");
|
||||
for (i = 0; i < 4; i += 1) {
|
||||
printf("%f\n", mytank.turret.desired);
|
||||
mytank.run(&mytank, mytank.udata);
|
||||
game.size[0] = 600;
|
||||
game.size[1] = 600;
|
||||
|
||||
printf("[\n");
|
||||
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;
|
||||
}
|
||||
|
|
93
trig.c
93
trig.c
|
@ -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
25
trig.h
|
@ -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__ */
|
Loading…
Reference in New Issue