1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-27 01:31:42 +00:00

Made an attempt to reintroduce missiles.

This commit is contained in:
Thomas Harte 2017-02-20 22:22:39 -05:00
parent 99547181f1
commit 7ab2358bba
2 changed files with 117 additions and 216 deletions

View File

@ -280,27 +280,28 @@ void TIA::set_playfield_ball_colour(uint8_t colour)
void TIA::set_player_number_and_size(int player, uint8_t value)
{
int size = 0;
switch(value & 7)
{
case 0: case 1: case 2: case 3: case 4:
player_[player].size = 0;
player_[player].copy_flags = value & 7;
break;
case 5:
player_[player].size = 1;
size = 1;
player_[player].copy_flags = 0;
break;
case 6:
player_[player].size = 0;
player_[player].copy_flags = 6;
break;
case 7:
player_[player].size = 2;
size = 2;
player_[player].copy_flags = 0;
break;
}
missile_[player].size = (value >> 4)&3;
missile_[player].size = 1 << ((value >> 4)&3);
missile_[player].copy_flags = player_[player].copy_flags;
player_[player].adder = 4 >> size;
}
void TIA::set_player_graphic(int player, uint8_t value)
@ -342,18 +343,23 @@ void TIA::set_player_missile_colour(int player, uint8_t colour)
void TIA::set_missile_enable(int missile, bool enabled)
{
missile_[missile].enabled = enabled;
}
void TIA::set_missile_position(int missile)
{
object_[(int)MotionIndex::Missile0 + missile].position = 0;
}
void TIA::set_missile_position_to_player(int missile)
{
// TODO: implement this correctly; should be triggered by player counter hitting the appropriate point
object_[(int)MotionIndex::Missile0 + missile].position = object_[(int)MotionIndex::Player0 + missile].position + 5;
}
void TIA::set_missile_motion(int missile, uint8_t motion)
{
object_[(int)MotionIndex::Missile0 + missile].motion = (motion >> 4)&0xf;
}
void TIA::set_ball_enable(bool enabled)
@ -371,7 +377,7 @@ void TIA::set_ball_position()
object_[(int)MotionIndex::Ball].position = 0;
// setting the ball position also triggers a draw
ball_.pixel_position = ball_.size;
ball_.reset_pixels();
}
void TIA::set_ball_motion(uint8_t motion)
@ -643,7 +649,7 @@ int TIA::perform_border_motion(Object &object, int start, int end)
return steps_taken;
}
template<class T> void TIA::draw_object(T &target, Object &object, int start, int end)
template<class T> void TIA::draw_object(T &target, Object &object, const uint8_t collision_identity, int start, int end)
{
int first_pixel = first_pixel_cycle - 4 + (horizontal_blank_extend_ ? 8 : 0);
@ -661,7 +667,7 @@ template<class T> void TIA::draw_object(T &target, Object &object, int start, in
// perform the visible part of the line, if any
if(start < 224)
{
draw_object_visible<T>(target, object, start - first_pixel_cycle + 4, std::min(end - first_pixel_cycle + 4, 160));
draw_object_visible<T>(target, object, collision_identity, start - first_pixel_cycle + 4, std::min(end - first_pixel_cycle + 4, 160));
}
// move further if required
@ -672,7 +678,7 @@ template<class T> void TIA::draw_object(T &target, Object &object, int start, in
}
}
template<class T> void TIA::draw_object_visible(T &target, Object &object, int start, int end)
template<class T> void TIA::draw_object_visible(T &target, Object &object, const uint8_t collision_identity, int start, int end)
{
// perform a miniature event loop on (i) triggering draws; (ii) drawing; and (iii) motion
int next_motion_time = object.motion_time - first_pixel_cycle + 4;
@ -708,7 +714,7 @@ template<class T> void TIA::draw_object_visible(T &target, Object &object, int s
// the decision is to progress by length
const int length = next_event_time - start;
target.draw_pixels(length);
target.draw_pixels(&collision_buffer_[start], length, collision_identity);
// the next interesting event is after next_event_time cycles, so progress
object.position = (object.position + length) % 160;
@ -731,209 +737,17 @@ template<class T> void TIA::draw_object_visible(T &target, Object &object, int s
#pragma mark - Player output
void TIA::draw_player_visible(Player &player, Object &object, CollisionType collision_identity, int start, int end)
{
int adder = 4 >> player.size;
// perform a miniature event loop on (i) triggering draws; (ii) drawing; and (iii) motion
int next_motion_time = object.motion_time - first_pixel_cycle + 4;
while(start < end)
{
int next_event_time = end;
// is the next event a movement tick?
if(object.is_moving && next_motion_time < next_event_time)
{
next_event_time = next_motion_time;
}
// is the next event a graphics trigger?
int next_copy = 160;
if(object.position < 16 && player.copy_flags&1)
{
next_copy = 16;
} else if(object.position < 32 && player.copy_flags&2)
{
next_copy = 32;
} else if(object.position < 64 && player.copy_flags&4)
{
next_copy = 64;
}
int next_copy_time = start + next_copy - object.position;
if(next_copy_time < next_event_time) next_event_time = next_copy_time;
// the decision is to progress by length
const int length = next_event_time - start;
if(player.pixel_position < 32)
{
player.pixel_position &= ~(adder - 1);
if(player.graphic[player.graphic_index])
{
int output_cursor = 0;
while(player.pixel_position < 32 && output_cursor < length)
{
int shift = (player.pixel_position >> 2) ^ player.reverse_mask;
collision_buffer_[start + output_cursor] |= ((player.graphic[player.graphic_index] >> shift)&1) * (uint8_t)collision_identity;
output_cursor++;
player.pixel_position += adder;
}
}
else
{
player.pixel_position = std::max(32, player.pixel_position + length * adder);
}
}
// the next interesting event is after next_event_time cycles, so progress
object.position = (object.position + length) % 160;
start = next_event_time;
// if the event is a motion tick, apply
if(object.is_moving && start == next_motion_time)
{
perform_motion_step(object);
next_motion_time += 4;
}
// if it's a draw trigger, trigger a draw
if(start == next_copy_time)
{
player.pixel_position = 0;
}
}
}
void TIA::draw_player(Player &player, Object &object, CollisionType collision_identity, int start, int end)
{
int adder = 4 >> player.size;
int first_pixel = first_pixel_cycle - 4 + (horizontal_blank_extend_ ? 8 : 0);
// movement works across the entire screen, so do work that falls outside of the pixel area
if(start < first_pixel)
{
player.pixel_position = std::min(32, player.pixel_position + adder * perform_border_motion(object, start, std::max(end, first_pixel)));
}
// don't continue to do any drawing if this window ends too early
if(end < first_pixel) return;
if(start < first_pixel) start = first_pixel;
if(start >= end) return;
// perform the visible part of the line, if any
if(start < 224)
{
draw_player_visible(player, object, collision_identity, start - first_pixel_cycle + 4, std::min(end - first_pixel_cycle + 4, 160));
}
// move further if required
if(object.is_moving && end >= 224 && object.motion_time < end)
{
perform_motion_step(object);
player.pixel_position = std::min(32, player.pixel_position + adder);
}
draw_object<Player>(player, object, (uint8_t)collision_identity, start, end);
}
#pragma mark - Missile output
void TIA::draw_missile(Missile &missile, Object &object, CollisionType collision_identity, int start, int end)
{
draw_object<Missile>(missile, object, (uint8_t)collision_identity, start, end);
}
void TIA::draw_missile_visible(Missile &missile, Object &object, CollisionType collision_identity, int start, int end)
{
}
#pragma mark - Ball output
void TIA::draw_ball(Object &object, int start, int end)
{
int first_pixel = first_pixel_cycle - 4 + (horizontal_blank_extend_ ? 8 : 0);
// movement works across the entire screen, so do work that falls outside of the pixel area
if(start < first_pixel)
{
ball_.pixel_position = std::max(0, ball_.pixel_position - perform_border_motion(object, start, std::max(end, first_pixel)));
}
// don't continue to do any drawing if this window ends too early
if(end < first_pixel) return;
if(start < first_pixel) start = first_pixel;
if(start >= end) return;
// perform the visible part of the line, if any
if(start < 224)
{
draw_ball_visible(object, start - first_pixel_cycle + 4, std::min(end - first_pixel_cycle + 4, 160));
}
// move further if required
if(object_[(int)MotionIndex::Ball].is_moving && end >= 224 && object_[(int)MotionIndex::Ball].motion_time < end)
{
perform_motion_step(object);
ball_.pixel_position = std::max(0, ball_.pixel_position - 1);
}
}
void TIA::draw_ball_visible(Object &object, int start, int end)
{
// perform a miniature event loop on (i) triggering draws; (ii) drawing; and (iii) motion
int next_motion_time = object.motion_time - first_pixel_cycle + 4;
while(start < end)
{
int next_event_time = end;
// is the next event a movement tick?
if(object.is_moving && next_motion_time < next_event_time)
{
next_event_time = next_motion_time;
}
// is the next event a graphics trigger?
if(ball_.enabled[ball_.enabled_index])
{
int time_until_copy = 160 - object.position;
int next_copy_time = start + time_until_copy;
if(next_copy_time < next_event_time) next_event_time = next_copy_time;
}
// the decision is to progress by length
const int length = next_event_time - start;
if(ball_.pixel_position)
{
int output_cursor = 0;
if(ball_.enabled[ball_.enabled_index])
{
while(ball_.pixel_position && output_cursor < length)
{
collision_buffer_[start + output_cursor] |= (uint8_t)CollisionType::Ball;
output_cursor++;
ball_.pixel_position--;
}
}
else
{
ball_.pixel_position = std::max(0, ball_.pixel_position - length);
}
}
// the next interesting event is after next_event_time cycles, so progress
object.position = (object.position + length) % 160;
start = next_event_time;
// if the event is a motion tick, apply
if(object.is_moving && start == next_motion_time)
{
perform_motion_step(object);
next_motion_time += 4;
}
// if it's a draw trigger, trigger a draw
if(!object.position)
{
ball_.pixel_position = ball_.size;
}
}
draw_object<Ball>(ball_, object, (uint8_t)CollisionType::Ball, start, end);
}

View File

@ -137,7 +137,7 @@ class TIA {
// player state
struct Player {
int size; // 0 = normal, 1 = double, 2 = quad
int adder;
int copy_flags; // a bit field, corresponding to the first few values of NUSIZ
uint8_t graphic[2]; // the player graphic; 1 = new, 0 = current
int reverse_mask; // 7 for a reflected player, 0 for normal
@ -145,12 +145,75 @@ class TIA {
int pixel_position;
Player() : size(0), copy_flags(0), graphic{0, 0}, reverse_mask(false), pixel_position(32), graphic_index(0) {}
inline void skip_pixels(int count)
{
pixel_position = std::min(32, pixel_position + count * adder);
}
inline void reset_pixels()
{
pixel_position = 0;
}
inline void draw_pixels(uint8_t *const target, const int count, const uint8_t collision_identity)
{
if(pixel_position == 32) return;
if(graphic[graphic_index])
{
int output_cursor = 0;
while(pixel_position < 32 && output_cursor < count)
{
int shift = (pixel_position >> 2) ^ reverse_mask;
target[output_cursor] |= ((graphic[graphic_index] >> shift)&1) * collision_identity;
output_cursor++;
pixel_position += adder;
}
}
else
{
skip_pixels(count);
}
}
Player() : copy_flags(0), graphic{0, 0}, reverse_mask(false), pixel_position(32), graphic_index(0) {}
} player_[2];
// missile state
struct Missile {
int size; // 0 = 1 pixel, 1 = 2 pixels, etc
bool enabled;
int size;
int copy_flags;
int pixel_position;
inline void skip_pixels(int count)
{
pixel_position = std::max(0, pixel_position - count);
}
inline void reset_pixels()
{
pixel_position = size;
}
inline void draw_pixels(uint8_t *const target, const int count, const uint8_t collision_identity)
{
if(!pixel_position) return;
if(enabled)
{
int output_cursor = 0;
while(pixel_position && output_cursor < count)
{
target[output_cursor] |= collision_identity;
output_cursor++;
pixel_position--;
}
}
else
{
skip_pixels(count);
}
}
} missile_[2];
// ball state
@ -158,9 +221,39 @@ class TIA {
bool enabled[2];
int enabled_index;
int size;
const int copy_flags = 0;
int pixel_position;
inline void skip_pixels(int count)
{
pixel_position = std::max(0, pixel_position - count);
}
inline void reset_pixels()
{
pixel_position = size;
}
inline void draw_pixels(uint8_t *const target, const int count, const uint8_t collision_identity)
{
if(!pixel_position) return;
if(enabled[enabled_index])
{
int output_cursor = 0;
while(pixel_position && output_cursor < count)
{
target[output_cursor] |= collision_identity;
output_cursor++;
pixel_position--;
}
}
else
{
skip_pixels(count);
}
}
Ball() : pixel_position(0), size(1), enabled_index(0) {}
} ball_;
@ -193,22 +286,16 @@ class TIA {
inline void perform_motion_step(Object &object);
// drawing methods and state
template<class T> void draw_object(T &, Object &, int start, int end);
template<class T> void draw_object_visible(T &, Object &, int start, int end);
template<class T> void draw_object(T &, Object &, const uint8_t collision_identity, int start, int end);
template<class T> void draw_object_visible(T &, Object &, const uint8_t collision_identity, int start, int end);
inline void output_for_cycles(int number_of_cycles);
inline void output_line();
inline void draw_playfield(int start, int end);
inline void draw_player(Player &player, Object &object, CollisionType collision_identity, int start, int end);
inline void draw_player_visible(Player &player, Object &object, CollisionType collision_identity, int start, int end);
inline void draw_missile(Missile &missile, Object &object, CollisionType collision_identity, int start, int end);
inline void draw_missile_visible(Missile &missile, Object &object, CollisionType collision_identity, int start, int end);
inline void draw_ball(Object &object, int start, int end);
inline void draw_ball_visible(Object &object, int start, int end);
int pixels_start_location_;
uint8_t *pixel_target_;