2004-11-09 12:29:25 -05:00
|
|
|
! A simple space shooter.
|
|
|
|
!
|
|
|
|
! To play the game:
|
|
|
|
!
|
|
|
|
! ./f factor.image -libraries:sdl=libSDL.so -libraries:sdl-gfx=libSDL_gfx.so
|
|
|
|
!
|
|
|
|
! "examples/factoroids.factor" run-file
|
|
|
|
|
2004-11-09 12:25:13 -05:00
|
|
|
IN: factoroids
|
|
|
|
|
|
|
|
USE: errors
|
|
|
|
USE: hashtables
|
|
|
|
USE: kernel
|
|
|
|
USE: lists
|
|
|
|
USE: logic
|
|
|
|
USE: math
|
|
|
|
USE: namespaces
|
2004-12-17 21:46:19 -05:00
|
|
|
USE: generic
|
2004-11-09 12:25:13 -05:00
|
|
|
USE: random
|
|
|
|
USE: sdl
|
2004-11-09 21:51:43 -05:00
|
|
|
USE: sdl-event
|
|
|
|
USE: sdl-gfx
|
|
|
|
USE: sdl-keysym
|
|
|
|
USE: sdl-video
|
2004-11-09 12:25:13 -05:00
|
|
|
|
|
|
|
! Game objects
|
2004-11-09 21:51:43 -05:00
|
|
|
GENERIC: draw ( actor -- )
|
2004-11-09 12:25:13 -05:00
|
|
|
#! Draw the actor.
|
|
|
|
|
2004-11-09 21:51:43 -05:00
|
|
|
GENERIC: tick ( actor -- ? )
|
2004-11-09 12:25:13 -05:00
|
|
|
#! Return f if the actor should be removed.
|
|
|
|
|
2004-11-09 21:51:43 -05:00
|
|
|
GENERIC: collide ( actor1 actor2 -- )
|
|
|
|
#! Handle collision of two actors.
|
|
|
|
|
2004-11-09 12:25:13 -05:00
|
|
|
! Actor attributes
|
2004-11-09 21:51:43 -05:00
|
|
|
SYMBOL: position
|
2004-11-09 12:25:13 -05:00
|
|
|
SYMBOL: radius
|
|
|
|
SYMBOL: len
|
2004-11-09 21:51:43 -05:00
|
|
|
SYMBOL: velocity
|
2004-11-09 12:25:13 -05:00
|
|
|
SYMBOL: color
|
2004-11-09 21:51:43 -05:00
|
|
|
SYMBOL: active
|
2004-11-09 12:25:13 -05:00
|
|
|
|
|
|
|
! The list of actors is divided into layers. Note that an
|
|
|
|
! actor's tick method can only add actors to layers other than
|
|
|
|
! the actor's layer. The player layer only has one actor.
|
|
|
|
SYMBOL: player
|
|
|
|
SYMBOL: enemies
|
|
|
|
SYMBOL: player-shots
|
|
|
|
SYMBOL: enemy-shots
|
|
|
|
|
2004-11-09 21:51:43 -05:00
|
|
|
: player-actor ( -- player )
|
|
|
|
player get dup [ car ] when ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
2004-11-09 21:51:43 -05:00
|
|
|
: x-in-screen? ( x -- ? ) 0 width get between? ;
|
|
|
|
: y-in-screen? ( y -- ? ) 0 height get between? ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
2004-11-09 21:51:43 -05:00
|
|
|
: in-screen? ( actor -- ? )
|
|
|
|
#! Is the actor in the screen?
|
|
|
|
[
|
|
|
|
position get >rect y-in-screen? swap x-in-screen? and
|
|
|
|
] bind ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
2004-11-09 21:51:43 -05:00
|
|
|
: move ( -- )
|
2004-11-09 12:25:13 -05:00
|
|
|
#! Add velocity vector to current actor's position vector.
|
2004-12-10 21:39:27 -05:00
|
|
|
velocity get position [ + ] change ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
2004-11-09 21:51:43 -05:00
|
|
|
: active? ( actor -- ? )
|
|
|
|
#! Push f if the actor should be removed.
|
|
|
|
[ active get ] bind ;
|
|
|
|
|
|
|
|
: deactivate ( actor -- )
|
|
|
|
#! Cause the actor to be removed in the next tick cycle.
|
|
|
|
[ active off ] bind ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
|
|
|
: screen-xy ( -- x y )
|
2004-11-09 21:51:43 -05:00
|
|
|
position get >rect swap >fixnum swap >fixnum ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
|
|
|
: actor-xy ( actor -- )
|
|
|
|
#! Copy actor's x/y co-ordinates to this namespace.
|
2004-11-09 21:51:43 -05:00
|
|
|
[ position get ] bind position set ;
|
|
|
|
|
|
|
|
! Collision detection
|
|
|
|
: distance ( actor1 actor2 -- x )
|
|
|
|
#! Distance between two actor's positions.
|
|
|
|
>r [ position get ] bind r> [ position get ] bind - abs ;
|
|
|
|
|
|
|
|
: min-distance ( actor1 actor2 -- )
|
|
|
|
#! Minimum distance before there is a collision.
|
|
|
|
>r [ radius get ] bind r> [ radius get ] bind + ;
|
|
|
|
|
|
|
|
: collision? ( actor1 actor2 -- ? )
|
|
|
|
2dup distance >r min-distance r> > ;
|
|
|
|
|
|
|
|
: check-collision ( actor1 actor2 -- )
|
|
|
|
2dup collision? [ collide ] [ 2drop ] ifte ;
|
|
|
|
|
|
|
|
: layer-actor-collision ( actor layer -- )
|
|
|
|
#! The layer is a list of actors.
|
|
|
|
[ dupd check-collision ] each drop ;
|
|
|
|
|
|
|
|
: layer-collision ( layer layer -- )
|
|
|
|
swap [ over layer-actor-collision ] each drop ;
|
|
|
|
|
|
|
|
: collisions ( -- )
|
|
|
|
#! Only collisions we allow are player colliding with an
|
|
|
|
#! enemy shot, and player shot colliding with enemy.
|
|
|
|
player get enemy-shots get layer-collision
|
|
|
|
enemies get player-shots get layer-collision ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
|
|
|
! The player's ship
|
2004-11-09 21:51:43 -05:00
|
|
|
|
2004-11-09 12:25:13 -05:00
|
|
|
TRAITS: ship
|
2004-11-09 21:51:43 -05:00
|
|
|
M: ship draw ( actor -- )
|
2004-11-09 12:25:13 -05:00
|
|
|
[
|
|
|
|
surface get screen-xy radius get color get
|
|
|
|
filledCircleColor
|
2004-12-17 21:46:19 -05:00
|
|
|
] bind ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
2004-12-17 21:46:19 -05:00
|
|
|
M: ship tick ( actor -- ? ) dup [ move ] bind active? ;
|
2004-11-09 21:51:43 -05:00
|
|
|
|
2004-12-17 21:46:19 -05:00
|
|
|
C: ship ( -- ship )
|
|
|
|
[
|
2004-11-09 21:51:43 -05:00
|
|
|
width get 2 /i height get 50 - rect> position set
|
|
|
|
white color set
|
|
|
|
10 radius set
|
|
|
|
0 velocity set
|
|
|
|
active on
|
2004-12-17 21:46:19 -05:00
|
|
|
] extend ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
|
|
|
! Projectiles
|
|
|
|
TRAITS: plasma
|
2004-11-09 21:51:43 -05:00
|
|
|
M: plasma draw ( actor -- )
|
2004-11-09 12:25:13 -05:00
|
|
|
[
|
|
|
|
surface get screen-xy dup len get + color get
|
|
|
|
vlineColor
|
2004-12-17 21:46:19 -05:00
|
|
|
] bind ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
2004-11-09 21:51:43 -05:00
|
|
|
M: plasma tick ( actor -- ? )
|
2004-12-17 21:46:19 -05:00
|
|
|
dup [ move ] bind dup in-screen? swap active? and ;
|
2004-11-09 21:51:43 -05:00
|
|
|
|
|
|
|
M: plasma collide ( actor1 actor2 -- )
|
|
|
|
#! Remove the other actor.
|
2004-12-17 21:46:19 -05:00
|
|
|
deactivate deactivate ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
2004-12-17 21:46:19 -05:00
|
|
|
C: plasma ( actor dy -- plasma )
|
|
|
|
[
|
2004-11-09 21:51:43 -05:00
|
|
|
velocity set
|
2004-11-09 12:25:13 -05:00
|
|
|
actor-xy
|
|
|
|
blue color set
|
|
|
|
10 len set
|
2004-11-09 21:51:43 -05:00
|
|
|
5 radius set
|
|
|
|
active on
|
2004-11-09 12:25:13 -05:00
|
|
|
] extend ;
|
|
|
|
|
|
|
|
: player-fire ( -- )
|
2004-11-09 21:51:43 -05:00
|
|
|
#! Do nothing if player is dead.
|
|
|
|
player-actor [
|
2004-12-17 21:46:19 -05:00
|
|
|
#{ 0 -6 } <plasma> player-shots cons@
|
2004-11-09 21:51:43 -05:00
|
|
|
] when* ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
|
|
|
: enemy-fire ( actor -- )
|
2004-12-17 21:46:19 -05:00
|
|
|
#{ 0 5 } <plasma> enemy-shots cons@ ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
|
|
|
! Background of stars
|
|
|
|
TRAITS: particle
|
|
|
|
|
2004-11-09 21:51:43 -05:00
|
|
|
M: particle draw ( actor -- )
|
2004-12-17 21:46:19 -05:00
|
|
|
[ surface get screen-xy color get pixelColor ] bind ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
|
|
|
: wrap ( -- )
|
|
|
|
#! If current actor has gone beyond screen bounds, move it
|
|
|
|
#! back.
|
2004-11-09 21:51:43 -05:00
|
|
|
position get >rect
|
|
|
|
swap >fixnum width get rem
|
|
|
|
swap >fixnum height get rem
|
|
|
|
rect> position set ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
2004-11-09 21:51:43 -05:00
|
|
|
M: particle tick ( actor -- )
|
2004-12-17 21:46:19 -05:00
|
|
|
[ move wrap t ] bind ;
|
|
|
|
|
|
|
|
C: particle ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
|
|
|
SYMBOL: stars
|
|
|
|
: star-count 100 ;
|
|
|
|
|
|
|
|
: random-x 0 width get random-int ;
|
|
|
|
: random-y 0 height get random-int ;
|
2004-11-09 21:51:43 -05:00
|
|
|
: random-position random-x random-y rect> ;
|
2004-11-09 12:25:13 -05:00
|
|
|
: random-byte 0 255 random-int ;
|
|
|
|
: random-color random-byte random-byte random-byte 255 rgba ;
|
2004-11-09 21:51:43 -05:00
|
|
|
: random-velocity 0 10 20 random-int 10 /f rect> ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
|
|
|
: random-star ( -- star )
|
|
|
|
<particle> [
|
2004-11-09 21:51:43 -05:00
|
|
|
random-position position set
|
2004-11-09 12:25:13 -05:00
|
|
|
random-color color set
|
2004-11-09 21:51:43 -05:00
|
|
|
random-velocity velocity set
|
|
|
|
active on
|
2004-11-09 12:25:13 -05:00
|
|
|
] extend ;
|
|
|
|
|
|
|
|
: init-stars ( -- )
|
2004-11-09 22:19:43 -05:00
|
|
|
#! Generate random background of scrolling stars.
|
2004-11-09 12:25:13 -05:00
|
|
|
[ ] star-count [ random-star swons ] times stars set ;
|
|
|
|
|
|
|
|
: draw-stars ( -- )
|
|
|
|
stars get [ draw ] each ;
|
|
|
|
|
|
|
|
: tick-stars ( -- )
|
|
|
|
stars get [ tick drop ] each ;
|
|
|
|
|
|
|
|
! Enemies
|
|
|
|
: enemy-chance 50 ;
|
|
|
|
|
|
|
|
TRAITS: enemy
|
2004-11-09 21:51:43 -05:00
|
|
|
M: enemy draw ( actor -- )
|
2004-11-09 12:25:13 -05:00
|
|
|
[
|
|
|
|
surface get screen-xy radius get color get
|
|
|
|
filledCircleColor
|
2004-12-17 21:46:19 -05:00
|
|
|
] bind ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
|
|
|
: attack-chance 30 ;
|
|
|
|
|
2004-12-10 21:39:27 -05:00
|
|
|
: chance ( n -- boolean )
|
|
|
|
#! Returns true with a 1/n probability, false with a (n-1)/n
|
|
|
|
#! probability.
|
|
|
|
1 swap random-int 1 = ;
|
|
|
|
|
2004-11-09 21:51:43 -05:00
|
|
|
: attack ( actor -- )
|
|
|
|
#! Fire a shot some of the time.
|
|
|
|
attack-chance chance [ enemy-fire ] [ drop ] ifte ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
|
|
|
SYMBOL: wiggle-x
|
|
|
|
|
|
|
|
: wiggle ( -- )
|
|
|
|
#! Wiggle from left to right.
|
2004-12-10 21:39:27 -05:00
|
|
|
-3 3 random-int wiggle-x [ + ] change
|
2004-11-09 21:51:43 -05:00
|
|
|
wiggle-x get sgn 1 rect> velocity set ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
2004-11-09 21:51:43 -05:00
|
|
|
M: enemy tick ( actor -- )
|
|
|
|
dup attack
|
|
|
|
dup [ wiggle move position get imaginary ] bind
|
2004-12-17 21:46:19 -05:00
|
|
|
y-in-screen? swap active? and ;
|
|
|
|
|
|
|
|
C: enemy ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
|
|
|
: spawn-enemy ( -- )
|
|
|
|
<enemy> [
|
2004-11-09 21:51:43 -05:00
|
|
|
random-x 10 rect> position set
|
2004-11-09 12:25:13 -05:00
|
|
|
red color set
|
|
|
|
0 wiggle-x set
|
2004-11-09 21:51:43 -05:00
|
|
|
0 velocity set
|
2004-11-09 12:25:13 -05:00
|
|
|
10 radius set
|
2004-11-09 21:51:43 -05:00
|
|
|
active on
|
2004-11-09 12:25:13 -05:00
|
|
|
] extend ;
|
|
|
|
|
|
|
|
: spawn-enemies ( -- )
|
|
|
|
enemy-chance chance [ spawn-enemy enemies cons@ ] when ;
|
|
|
|
|
|
|
|
! Event handling
|
|
|
|
SYMBOL: event
|
|
|
|
|
|
|
|
: mouse-motion-event ( event -- )
|
2004-11-09 21:51:43 -05:00
|
|
|
motion-event-x player-actor dup [
|
|
|
|
[ position get imaginary rect> position set ] bind
|
|
|
|
] [
|
|
|
|
2drop
|
|
|
|
] ifte ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
|
|
|
: mouse-down-event ( event -- )
|
|
|
|
drop player-fire ;
|
|
|
|
|
|
|
|
: handle-event ( event -- ? )
|
|
|
|
#! Return if we should continue or stop.
|
|
|
|
[
|
|
|
|
[ event-type SDL_MOUSEBUTTONDOWN = ] [ mouse-down-event t ]
|
|
|
|
[ event-type SDL_MOUSEMOTION = ] [ mouse-motion-event t ]
|
|
|
|
[ event-type SDL_QUIT = ] [ drop f ]
|
|
|
|
[ drop t ] [ drop t ]
|
|
|
|
] cond ;
|
|
|
|
|
|
|
|
: check-event ( -- ? )
|
|
|
|
#! Check if there is a pending event.
|
|
|
|
#! Return if we should continue or stop.
|
|
|
|
event get dup SDL_PollEvent [
|
|
|
|
handle-event [ check-event ] [ f ] ifte
|
|
|
|
] [
|
|
|
|
drop t
|
|
|
|
] ifte ;
|
|
|
|
|
|
|
|
! Game loop
|
|
|
|
: init-game ( -- )
|
|
|
|
#! Init game objects.
|
2004-11-09 21:51:43 -05:00
|
|
|
init-stars
|
2004-12-17 21:46:19 -05:00
|
|
|
<ship> unit player set
|
2004-11-09 21:51:43 -05:00
|
|
|
<event> event set ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
|
|
|
: each-layer ( quot -- )
|
|
|
|
#! Apply quotation to each layer.
|
|
|
|
[ enemies enemy-shots player player-shots ] swap each ;
|
|
|
|
|
|
|
|
: draw-actors ( -- )
|
2004-11-09 21:51:43 -05:00
|
|
|
[ get [ draw ] each ] each-layer ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
|
|
|
: tick-actors ( -- )
|
2004-11-09 21:51:43 -05:00
|
|
|
#! Advance game state by one frame. Actors whose tick word
|
|
|
|
#! returns f are removed from the layer.
|
|
|
|
[ dup get [ tick ] subset put ] each-layer ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
|
|
|
: render ( -- )
|
|
|
|
#! Draw the scene.
|
2004-11-09 21:51:43 -05:00
|
|
|
[ black clear-surface draw-stars draw-actors ] with-surface ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
|
|
|
: advance ( -- )
|
|
|
|
#! Advance game state by one frame.
|
|
|
|
tick-actors tick-stars spawn-enemies ;
|
|
|
|
|
|
|
|
: game-loop ( -- )
|
|
|
|
#! Render, advance game state, repeat.
|
2004-11-09 21:51:43 -05:00
|
|
|
render advance collisions check-event [ game-loop ] when ;
|
2004-11-09 12:25:13 -05:00
|
|
|
|
|
|
|
: factoroids ( -- )
|
|
|
|
#! Main word.
|
|
|
|
640 480 32 SDL_HWSURFACE [
|
|
|
|
"Factoroids" "Factoroids" SDL_WM_SetCaption
|
|
|
|
init-game game-loop
|
|
|
|
] with-screen ;
|
|
|
|
|
|
|
|
factoroids
|