|
=effect instant |
|
=font FreeMono.ttf |
|
|
|
========== |
|
|
|
# momentum... those nice arcing jumps and flaps |
|
# every enemy I add takes 6 bytes of data and removes 6 lines of display |
|
|
|
=background_image speed.png |
|
|
|
========== |
|
|
|
=clear_background 1 |
|
|
|
=font_size 8 |
|
|
|
# speed |
|
|
|
momentum0 |
|
; control loops back here when we iterate over the movable bodies |
|
lda playerzspeed,x |
|
bmi momentum1 |
|
; positive case |
|
clc |
|
adc playerzlo,x |
|
sta playerzlo,x |
|
bvc momentum2 ; overflow means we need to carry from our signed playerzlo into the unsigned playerz. if no overflow so we didn't go above 127. go on to dealing with Y speed. |
|
clc |
|
lda playerz,x |
|
adc #01 |
|
; bcs momentum2 ; branch if we carried; don't wrap playerz above 255 XXX actually, wouldn't this be the win condition for the level? XXX I might be dreaming, but it seems like wrapping around the edge of a level actually works |
|
sta playerz,x |
|
jmp momentum2 |
|
momentum1 |
|
; playerzspeed is negative |
|
_absolute ; absolute value of playerzspeed |
|
sta tmp1 |
|
lda playerzlo,x |
|
sec |
|
sbc tmp1 |
|
sta playerzlo,x |
|
lda playerz,x |
|
; beq momentum1a ; but don't go below 0; XXX testing; actually, we do want enemies flying towards us to be able to warp off the end of the level |
|
sbc #0 ; if we barrowed above, this will effective decrement playerz by one |
|
sta playerz,x |
|
momentum1a |
|
|
|
========== |
|
|
|
=clear_background 1 |
|
|
|
=font_size 20 |
|
|
|
# speed |
|
|
|
momentum0 |
|
; control loops back here when we iterate over the movable bodies |
|
lda playerzspeed,x |
|
bmi momentum1 |
|
; positive case |
|
clc |
|
adc playerzlo,x |
|
sta playerzlo,x |
|
bvc momentum2 |
|
clc |
|
lda playerz,x |
|
adc #01 |
|
; bcs momentum2 |
|
sta playerz,x |
|
jmp momentum2 |
|
momentum1 |
|
; playerzspeed is negative |
|
_absolute |
|
sta tmp1 |
|
lda playerzlo,x |
|
sec |
|
sbc tmp1 |
|
sta playerzlo,x |
|
lda playerz,x |
|
; beq momentum1a |
|
sbc #0 |
|
sta playerz,x |
|
momentum1a |
|
|
|
|
|
=============== |
|
|
|
# Rotation Function |
|
|
|
Vx'=rot((x,0),a) = (x*cos(a) ,x*sin(a)) |
|
+ Vy'=rot((0,y),a) = ( +y*sin(a), -y*cos(a)) |
|
---------------------------------------------------------- |
|
V' =rot((x,y),a) = (x*cos(a)+y*sin(a),x*sin(a)-y*cos(a)) |
|
|
|
# We don't do that. |
|
# Instead, view is fixed straight ahead. |
|
|
|
========== |
|
|
|
# Projection Function |
|
|
|
New Y=k*y/(z+dist) |
|
X=k*x/(z+dist) |
|
|
|
# we don't use that. |
|
|
|
============= |
|
|
|
=background_image render_overview.png |
|
|
|
|
|
|
|
|
|
============= |
|
|
|
=clear_background 1 |
|
|
|
# _arctan |
|
|
|
# "arctangent can find the angle given the ratio of two sides of a right triangle" |
|
|
|
# there's a right triangle between us and the object we're rendering: |
|
# playerz - objectz, playery - objecty |
|
|
|
# the arctangent table is indexed by the ratio of the y and z deltas |
|
# we use the most significant non-zero four bits of each delta |
|
|
|
# table only has things in our field of view. ie, |
|
# atan(z/y) normalized to between 0 and #(viewsize/2) instead of taking rads or degrees |
|
|
|
# the perl code is inline in the 6502 code; asm uses the semicolon to indicate a comment. found that handy. |
|
|
|
# XXX look at the JS raycaster page |
|
|
|
; use Math::Trig; |
|
; my $scanlines = 107; |
|
; my $max = int($scanlines / 2); $max-- if(( $scalines & 0b01) == 0); |
|
; my $field_of_view_in_angles = 90; |
|
; my $multiplier = $scanlines / $field_of_view_in_angles; |
|
; for my $y (0..15) { |
|
; my @z = $y+1 .. $y+16; |
|
; print "\t\t; z = @{[ join ', ', @z ]}\n"; |
|
; print "\t\tdc.b "; |
|
; for my $z (@z) { |
|
; if( $z == 0 ) { print '%0000000, '; next; } |
|
; my $angle = int(rad2deg(atan($y/$z))*$multiplier); |
|
; print $angle; |
|
; print ", " if $z != $z[-1]; |
|
; } |
|
; print "; y = $y\n"; |
|
; } |
|
; print "\n"; |
|
|
|
|
|
============= |
|
|
|
arctangent |
|
|
|
; z = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 |
|
dc.b 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; y = 0 |
|
; z = 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 |
|
dc.b 31, 21, 16, 13, 11, 9, 8, 7, 6, 6, 5, 5, 4, 4, 4, 4; y = 1 |
|
; z = 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 |
|
dc.b 40, 31, 25, 21, 18, 16, 14, 13, 12, 11, 10, 9, 9, 8, 7, 7; y = 2 |
|
; z = 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 |
|
dc.b 43, 36, 31, 27, 24, 21, 19, 18, 16, 15, 14, 13, 12, 11, 11, 10; y = 3 |
|
; z = 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 |
|
dc.b 45, 40, 35, 31, 28, 25, 23, 21, 20, 18, 17, 16, 15, 14, 14, 13; y = 4 |
|
; z = 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 |
|
dc.b 47, 42, 38, 34, 31, 29, 26, 25, 23, 21, 20, 19, 18, 17, 16, 15; y = 5 |
|
; z = 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 |
|
dc.b 48, 43, 40, 36, 34, 31, 29, 27, 25, 24, 23, 21, 20, 19, 18, 18; y = 6 |
|
; z = 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 |
|
dc.b 48, 45, 41, 38, 35, 33, 31, 29, 28, 26, 25, 24, 22, 21, 20, 20; y = 7 |
|
; z = 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 |
|
dc.b 49, 45, 42, 40, 37, 35, 33, 31, 29, 28, 27, 25, 24, 23, 22, 21; y = 8 |
|
; z = 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 |
|
dc.b 49, 46, 43, 41, 38, 36, 34, 33, 31, 30, 28, 27, 26, 25, 24, 23; y = 9 |
|
; z = 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 |
|
dc.b 50, 47, 44, 42, 40, 38, 36, 34, 33, 31, 30, 29, 27, 26, 25, 25; y = 10 |
|
; z = 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 |
|
dc.b 50, 47, 45, 43, 41, 39, 37, 35, 34, 32, 31, 30, 29, 28, 27, 26; y = 11 |
|
; z = 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 |
|
dc.b 50, 48, 45, 43, 41, 40, 38, 36, 35, 34, 32, 31, 30, 29, 28, 27; y = 12 |
|
; z = 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 |
|
dc.b 50, 48, 46, 44, 42, 40, 39, 37, 36, 35, 33, 32, 31, 30, 29, 28; y = 13 |
|
; z = 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 |
|
dc.b 51, 48, 46, 45, 43, 41, 40, 38, 37, 35, 34, 33, 32, 31, 30, 29; y = 14 |
|
; z = 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 |
|
dc.b 51, 49, 47, 45, 43, 42, 40, 39, 38, 36, 35, 34, 33, 32, 31, 30; y = 15 |
|
|
|
|
|
=============== |
|
|
|
=font_size 12 |
|
|
|
.platlinedelta |
|
lda deltay |
|
beq .platlinedeltastuff2 ; stuff the case where deltay = 0 |
|
|
|
_absolute |
|
sta tmp2 ; tmp2 has abs(deltay) |
|
|
|
cmp deltaz ; is deltaz = deltay? |
|
bne .platlinedeltago ; branch on the normal case where deltaz != deltay |
|
|
|
.platlinedeltastuff0 |
|
; deltaz = deltay or deltaz = 0; stuff the return value to be the very top or very bottom scanline, depending |
|
bit deltay |
|
bpl .platlinedeltastuff1 |
|
; platform is above us |
|
lda #[viewsize - 1] ; is this correct? XXX or are we off by one? |
|
jmp .platarctan9 |
|
.platlinedeltastuff1 |
|
; platform is below us |
|
lda #0 |
|
jmp .platarctan9 |
|
|
|
.platlinedeltastuff2 |
|
lda #[viewsize/2] |
|
bne .platarctan9 |
|
|
|
.platlinedeltago |
|
lda deltaz |
|
beq .platlinedeltastuff0 ; stuff the case where deltaz = 0 |
|
sec |
|
sbc tmp2 |
|
sta tmp1 ; tmp1 has deltaz - abs(deltay) |
|
ora tmp2 ; combined bits so we only have to test one value to see if all bits are clear of the top nibble |
|
.platlinedeltaagain |
|
cmp #$0F |
|
bmi .platlinedeltadone ; 0F is larger, had to barrow, so we know that no high nibble bits are set |
|
lsr |
|
lsr tmp1 |
|
lsr tmp2 |
|
jmp .platlinedeltaagain |
|
.platlinedeltadone |
|
lda tmp2 ; table loops over $z then over $y, so $z is down and $y is across |
|
asl ; tmp1 is our deltaz, tmp2 our deltay |
|
asl ; so we make tmp1 our high nibble so it goes down and tmp2 our low nibble so it goes across |
|
asl |
|
asl |
|
ora tmp1 |
|
tay |
|
bit deltay ; handle the separate cases of the platform above us and the platform below us |
|
bpl .platarctan1 ; branch if deltay is positive; this means that the platform is lower than us |
|
lda arctangent,y ; platform is above us; add the arctangent value to the middle of the screen |
|
clc |
|
adc #(viewsize/2) ; 'view' is upside down, so adding relative to the middle of it moves things towards the top of the screen |
|
jmp .platarctan9 |
|
.platarctan1 |
|
lda #(viewsize/2) ; platform is below us; subtract the arctangent value from the middle of the screen |
|
sec |
|
sbc arctangent,y ; 'view' is upside down, so subtracting relative the middle of it moves things towards the bottom of the screen |
|
; negative value indicates off screen angle; return the negative value to proprogate the error |
|
.platarctan9 |
|
|
|
==================================== |
|
|
|
# hypot unit test |
|
|
|
=font_size 16 |
|
|
|
use Test::More; |
|
use Acme::6502; |
|
|
|
use symbols; |
|
|
|
my $symbols = symbols::symbols('newbies.lst'); |
|
|
|
my $cpu = Acme::6502->new(); |
|
$cpu->load_rom( 'newbies.bin', 0xf000 ); |
|
|
|
sub run_cpu { |
|
$cpu->run(10000, sub { |
|
my ($pc, $inst, $a, $x, $y, $s, $p) = @_; |
|
if( $pc == $symbols->{'.plot9'} ) { |
|
${ PadWalker::peek_my(1)->{'$ic'} } = 0; |
|
} |
|
}); |
|
} |
|
|
|
my $view = $symbols->view; |
|
my $viewsize = 0xff - $view; |
|
|
|
==================================== |
|
|
|
=font_size 16 |
|
|
|
# hypot unit test |
|
|
|
$cpu->write_8( $symbols->curplat, 0 ); # controls what color the line drawn will be |
|
$cpu->write_8( $symbols->lastline, 0xff ); |
|
|
|
ok my $expected_width = $cpu->read_8( $symbols->perspectivetable + 10 ), 'there is an expected width'; |
|
ok my $expected_color = $cpu->read_8( $symbols->level0 + 0 + 3 ), 'there is an expected color'; |
|
|
|
is $cpu->read_8( $symbols->view + 50 ), 0, "is line 50 blank to start with?"; |
|
|
|
# Y gets the distance, which we use to figure out which size of line to draw |
|
# X gets the scan line to draw at |
|
|
|
$cpu->set_pc($symbols->{'.plotonscreen'}); |
|
|
|
$cpu->set_y( 10 ); |
|
$cpu->set_x( 50 ); |
|
|
|
run_cpu(); |
|
|
|
my $line = $cpu->read_8( $symbols->view + 50 ); |
|
is $line & 0b11100000, $expected_color, "line drawn with expected color"; |
|
is $line & 0b00011111, $expected_width, "line drawn with expected width"; |
|
|
|
|
|
|
|
|
|
==================== |
|
|
|
# _plathypot |
|
|
|
=background_image hypot.jpg |
|
|
|
=================== |
|
|
|
# _plathypot |
|
|
|
=clear_background 1 |
|
|
|
=font_size 18 |
|
|
|
# add zdelta back into zdelta a fractional number of times depending on ydelta |
|
|
|
lda deltay |
|
_absolute |
|
tay |
|
lda distancemods,y |
|
sta tmp2 ; top three bits indicate whether 1/4th of deltaz should be re-added to itself, then 1/8th, etc |
|
lda deltaz |
|
lsr |
|
lsr |
|
sta tmp1 ; tmp1 contains the fractional (1/4 at first, then 1/8th, then 1/16th) value of deltaz |
|
lda deltaz ; fresh copy to add fractional parts to |
|
clc |
|
asl tmp2 |
|
bcc .plathypot1 |
|
clc |
|
adc tmp1 ; 1/4 |
|
.plathypot1 |
|
lsr tmp1 ; half again |
|
asl tmp2 |
|
bcc .plathypot2 |
|
clc |
|
adc tmp1 ; 1/8th |
|
.plathypot2 |
|
lsr tmp1 ; half again |
|
asl tmp2 |
|
bcc .plathypot3 |
|
clc |
|
adc tmp1 ; 1/16th |
|
.plathypot3 |
|
|
|
======================== |
|
|
|
=font_size 16 |
|
|
|
=clear_background 1 |
|
|
|
$cpu->set_pc( $symbols->platrenderline ); |
|
$cpu->write_8( $symbols->deltaz, 2 ); |
|
$cpu->write_8( $symbols->deltay, 2 ); |
|
run_cpu( $symbols->platrenderline1, $symbols->platnext ); |
|
is $cpu->get_pc, $symbols->platrenderline1 + 2, "deltaz = 2, deltay = 2 slope"; |
|
|
|
|
|
==================== |
|
|
|
=font_size 16 |
|
|
|
# _plotonscreen |
|
|
|
.plot_down1 |
|
lda view,x ; +4 9 get the line width of what's there already |
|
and #%00011111 ; +2 11 mask off the color part and any other data |
|
cmp perspectivetable,y ; +4 15 compare to the fatness of line we wanted to draw |
|
bpl .plot_down2 ; +2 17 what we wanted to draw is smaller. skip it. |
|
|
|
lda perspectivetable,y ; +4 21 perspectivetable translates distance to on-screen line width |
|
ora tmp2 ; +3 24 add the platform color |
|
sta view,x ; +4 28 draw to the framebuffer |
|
|
|
.plot_down2 |
|
cpx lastline ; +3 31 we want to catch it at 1 diff |
|
beq .plot8 ; +2 33 if lastline minus curline is exactly 1 away, we're done |
|
.plot_down2a |
|
dex ; +2 35 drawing downwards relative last plot |
|
lda INTIM ; +2 2 worst case scenario, we read this as a '1' one cycle before 0 |
|
bne .plot_down1 ; +3 5 |
|
_vsync ; do the next vsync/vblank thing that needs to be done and then |
|
; put more time on the timer, or else jump to start |
|
bne .plot_down1 ; loop always |
|
|
|
|
|
=========================== |
|
|
|
=font_size 14 |
|
|
|
open my $fh, '6502_formatted.txt' or die $!; |
|
while( my $line = readline $fh ) { |
|
chomp $line; |
|
my @line = split m/ /, $line; |
|
$cycles_per_opcode->[ hex($line[0]) ] = $line[1]; |
|
} |
|
|
|
sub run_cpu { |
|
my @stop_symbols = @_; |
|
my $cycles = 0; |
|
$cpu->run(100000, sub { |
|
my ($pc, $inst, $a, $x, $y, $s, $p) = @_; |
|
$cycles_per_opcode->[$inst] or die sprintf( "%2x (%d) has no cycle count", $inst, $inst) . "\n" . Dumper( $cycles_per_opcode ); |
|
$cycles += $cycles_per_opcode->[$inst]; |
|
if( grep $pc == $_, @stop_symbols ) { |
|
${ PadWalker::peek_my(1)->{'$ic'} } = 0; |
|
} |
|
}); |
|
return $cycles; |
|
} |
|
|
|
========================== |
|
|
|
# XXX counting cycles |
|
|
|
# unit testing runtime |
|
|
|
=font_size 16 |
|
|
|
$cpu->set_pc( $symbols->platlevelclear ); |
|
$cpu->write_8( $symbols->playerz, 0x00 ); |
|
$cpu->write_8( $symbols->playery, 0x20 ); |
|
|
|
$cycles = run_cpu( $symbols->vblanktimerendalmost ); |
|
|
|
diag "ran in $cycles cycles"; # 10744 |
|
ok $cycles < $available_cycles, "finishes in less than $available_cycles cycles"; |
|
|
|
|
|
|
|
================ |
|
|
|
=font_size 16 |
|
|
|
# unit testing timers/hardware registers |
|
|
|
perldoc Acme::6502 says: |
|
|
|
BUGS AND LIMITATIONS |
|
Doesn't have support for hardware emulation hooks - so memory |
|
mapped I/O is out of the question until someone fixes it. |
|
|
|
======================= |
|
|
|
# unit testing timers/hardware registers |
|
|
|
=clear_background 1 |
|
|
|
=font_size 16 |
|
|
|
package Register::TIM64T { |
|
# start a new timer |
|
use base 'Tie::StdScalar'; |
|
sub TIESCALAR { my $class = shift; $_[0] ||= 0; return bless \$_[0] => $class; } |
|
sub STORE { |
|
$timer_cycles = $cycles; |
|
${$_[0]} = $_[1]; |
|
} |
|
}; |
|
|
|
tie $cpu->{mem}->[ $symbols->TIM64T ], 'Register::TIM64T'; |
|
|
|
package Register::INTIM { |
|
# read the timer |
|
use base 'Tie::StdScalar'; |
|
sub TIESCALAR { my $class = shift; $_[0] ||= 0; return bless \$_[0] => $class; } |
|
sub FETCH { |
|
my $ret = $cpu->{mem}->[ $symbols->TIM64T ] - int( ( $cycles - $timer_cycles ) / 64 ); |
|
$last_intim_value = $ret; |
|
$ret; |
|
} |
|
}; |
|
|
|
tie $cpu->{mem}->[ $symbols->INTIM ], 'Register::INTIM'; |
|
|
|
========================= |
|
|
|
# unit testing timers/hardware registers |
|
|
|
=clear_background 1 |
|
|
|
=font_size 16 |
|
|
|
$cpu->write_8( $symbols->TIM64T, 76 ); |
|
|
|
diag "code is checking timer against this constant: " . $cpu->read_8( $symbols->platnextline0a+1 ); |
|
|
|
$cpu->set_pc( $symbols->platlevelclear ); |
|
$cpu->write_8( $symbols->playerz, 0x00 ); |
|
$cpu->write_8( $symbols->playery, 0x1F ); |
|
|
|
run_cpu( $symbols->vblanktimerendalmost, $symbols->startofframe ); |
|
|
|
diag "stopped at symbol " . $symbols->name_that_location( $cpu->get_pc ); |
|
ok ! $ran_out_of_time, "didn't run out of time"; |
|
|
|
========================================== |
|
|
|
# display kernel |
|
|
|
=clear_background 1 |
|
|
|
=font_size 16 |
|
|
|
; get COLUPF, COLUBK, and scanline values ready to roll |
|
|
|
ldy scanline ; +3 36 (33 when execution arrives) |
|
|
|
; get value for COLUPF ready in Y |
|
lax view,y ; +4 40 |
|
ldy platformcolors,x; +4 44 |
|
|
|
; if the looked up color is $00, skip redrawing CULUPF, COLUBK, and the |
|
; PF registers to instead update the player registers |
|
beq enemy ; +2 46 |
|
|
|
; get the pf*lookup index ready in X |
|
and #%00011111 ; +2 48 |
|
tax ; +2 50 |
|
|
|
; get value for COLUBK somewhat setup in A |
|
lda scanline ; +3 53 |
|
adc skyline ; +3 56 |
|
|
|
nop ; +2 58 ... XXX 12 bonus cycles |
|
nop ; +2 60 |
|
nop ; +2 62 |
|
nop ; +2 64 |
|
nop ; +2 66 |
|
nop ; +2 68 |
|
|
|
dec scanline ; +5 73 |
|
bpl platforms ; +3 76 |
|
; (counting the case where it's taken; this has to come out to exactly 76 cycles) |
|
|
|
========================================== |
|
|
|
# display kernel |
|
|
|
=clear_background 1 |
|
|
|
=font_size 16 |
|
|
|
# drawing starts on cycle 22 |
|
|
|
platforms |
|
|
|
sty COLUPF ; +3 3 |
|
|
|
tay ; +2 5 |
|
lda background,y ; +4 9 |
|
sta COLUBK ; +3 12 |
|
|
|
lda pf0lookup,x ; +4 16 |
|
sta PF0 ; +3 19 ... this needs to happen sometime on or before cycle 22 |
|
lda pf1lookup,x ; +4 23 |
|
sta PF1 ; +3 26 ... this needs to happen some time before cycle 28 |
|
lda pf2lookup,x ; +4 30 |
|
sta PF2 ; +3 33 |
|
|
|
|
|
========================================== |
|
|
|
=background_image newbiesrender.jpg |
|
|
|
=========================================== |
|
|
|
# notes on my stuff: |
|
|
|
# no use of jsr/rts. don't want to use the two bytes of RAM for one level of nesting, and I'm using the S register to hold stuff. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
============== |
|
|
|
# Current Status of 2600 Development |
|
|
|
# current status... |
|
|
|
=background_image melody_board.jpg |
|
|
|
# advanced topics: asserting the bus |
|
# ARM processors in the cart |
|
# open source style knowledge sharing |
|
# active community on atariage.com |
|
# new homebrews finished every year, and for sale |
|
|
|
=========================== |
|
|
|
=font_size 18 |
|
|
|
level3 |
|
playfield: |
|
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
|
X..............................X |
|
...............................X |
|
XXXXXXXXXXXXXXXXXX.............X |
|
X..............................X |
|
X..............................X |
|
X......................XXXXXXXXX |
|
X..............................X |
|
X.....XXXXXXXXXXX..............X |
|
X..............................X |
|
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
|
end |
|
ballx = 19 : bally = 19 |
|
return |
|
|
|
=============================== |
|
|
|
=font_size 16 |
|
|
|
rem check for portal collision and overwrite the initial portal with the new one |
|
if collision(missile0,missile1) && m0_shot{0} then missile1x = 255 : missile1y = 255 : m1_persistence{1}=0 |
|
if collision(missile0, missile1) && m1_shot{1} then missile0x = 255 : missile0y = 255 : m0_persistence{0}=0 |
|
|
|
if collision(missile0,ball) then missile0x = 255 : missile0y = 255 : m0_persistence{0}=0 |
|
if collision(missile1,ball) then missile1x = 255 : missile1y = 255 : m1_persistence{1}=0 |
|
|
|
rem check to see if a moving portal hit the playfield and if so then stop moving and make it active |
|
rem also disregard portals that are designated inactive |
|
if collision(missile1,playfield) && missile1x < 255 then m1_shot{1}=0 : m1_persistence{1}=1 |
|
if collision(missile0,playfield) && missile0x < 255 then m0_shot{0}=0 : m0_persistence{0}=1 |
|
|
|
rem see if the player is accessing a portal and change their position to the other one |
|
if collision(player1,missile0) && m1_persistence{1} then gosub player_pos1 |
|
if collision(player1,missile1) && m0_persistence{0} then gosub player_pos0 |
|
|
|
|
|
|
|
============= |
|
|
|
# Conclusion |
|
|
|
=background_image portal.bas.png |
|
|
|
# 14 year production run. |
|
|
|
# fun to optimize and polish and rewrite and rewrite a small bit of code |
|
|
|
# It's all about gameplay. What makes the game tick? What's the essential element? |
|
# It doesn't take much RAM get gameplay right. |
|
|
|
|
|
|
|
=================== |
|
|
|
END |
|
|
|
|
|
============= |
|
|
|
|
|
|
|
|
|
|
|
============= |
|
|
|
# fodder |
|
|
|
=background_image perlprogramming.png |
|
|