First of all let's create an image. Rebol has many images inside, one of the is old icon image:
to see it:
view layout [icon]
The game script shows just column of 4 pixel (see last post), so we need to divide enlarge and divide the image:
;let's create the image using the an rebol internal image:
layout [temp: icon]
my_image: temp/pane/image ;icon is ane image 48x48
layout [temp: image my_image 1024x1024 ]
my_image: to-image temp
; now we slices in columns the image
imgs: copy []
size: 4x1024 ; width and height of each subimage
reps: my_image/size / size ;number of repetions
repeat y reps/y [
repeat x reps/x [
xy: size * as-pair x - 1 y - 1
append imgs copy/part at my_image xy size
]
]
thelay: copy []
a: 1
b: 4
foreach item imgs [append thelay reduce ['image item (as-pair a 1) (as-pair b 1024 )]
a: a + 4
b: b + 4
]
view layout [box 1024x1024 effect [ draw thelay ]]
This will be the result:
Ok, now just decide a color, for example 4 of the map, will be a block with this image and we'll substitute the color slice with the image slice. A simple calculus will indicate wich slice to use, and the xx position if it's an horizontal wall or a vertical wall:
Here the commented source:
REBOL [
subject: "raycasting engine"
version: 0.8
]
;let's create the image using the an rebol internal image:
layout [temp: icon]
my_image: temp/pane/image ;icon is ane image 48x48
layout [temp: image my_image 1024x1024 ]
my_image: to-image temp
; now we slices in columns the image
imgs: copy []
size: 4x1024 ; width and height of each subimage
reps: my_image/size / size ;number of repetions
repeat y reps/y [
repeat x reps/x [
xy: size * as-pair x - 1 y - 1
append imgs copy/part at my_image xy size
]
]
;note some values are scaled to 1024 to create smooth movements
px: 9 * 1024 ; initial position
py: 11 * 1024 ; initial position
stride: 5 ;step
heading: 0 ;initial view (degree)
turn: 10 ;rotating step
;labirinth map
laby: [
[ 8 7 8 7 8 7 8 7 8 7 8 7 ]
[7 0 0 0 0 0 0 0 13 0 0 8 ]
[8 0 0 0 12 0 0 0 14 0 9 7 ]
[7 0 0 0 12 0 4 0 13 0 0 8 ]
[8 0 4 11 11 0 3 0 0 0 0 7 ]
[7 0 3 0 12 3 4 3 4 3 0 8 ]
[8 0 4 0 0 0 3 0 3 0 0 7 ]
[7 0 3 0 0 0 4 0 4 0 9 8 ]
[8 0 4 0 0 0 0 0 0 0 0 7 ]
[7 0 5 6 5 6 0 0 0 0 0 8 ]
[8 0 0 0 0 0 0 0 0 0 0 7 ]
[8 7 8 7 8 7 8 7 8 7 8 7 ]
]
;function to scale the projection of the ray
get-angle: func [v ] [to-integer (((cosine v ) * 1024) / 10 )]
get-angles: func [v ] [to-integer (((sine v ) * 1024) / 10)]
;colors
palette: [
0.0.128
0.128.0
0.128.128
0.0.128
128.0.128
128.128.0
192.192.192
128.128.128
0.0.255
0.255.0
255.255.0
0.0.255
255.0.255
0.255.255
255.255.255
]
;this will be player view
screen: layout [
display: box 360x200 effect [
gradient 0x1 0.0.0 128.128.128
draw []
] edge [
size: 1x1
color: 255.255.255
]
]
;main function to raycasting
retrace: does [
clear display/effect/draw
xy1: 0x0
xy2: 4x0
angle: remainder (heading - 44) 360 ;this formula put angle between 0 and 359, and since the angle of view (heading) is in the middle of the cone, put the scanning ray at the beggining of the view
if angle < 0 [ angle: angle + 360 ] ;this make alway positive the angle
;starting scanning
temp: copy []
for a angle (angle + 89) 1 [
;temporary coordinates
xx: px
yy: py
;get the ray direction
stepx: get-angles a
stepy: get-angle a
;distance or lenght of the ray fro eyes to the wall
l: 0
until [
;walk in the current ray direction in order to find a wall
xx: xx - stepx
yy: yy - stepy
l: l + 1
column: to-integer (xx / 1024)
line: to-integer (yy / 1024)
laby/:line/:column <> 0
]
h: to-integer (900 / l)
xy1/y: 100 - h
xy2/y: 100 + h
color: pick palette laby/:line/:column
; block with color 4 will be our blocks with image
either laby/:line/:column = 4 [
slice: to-integer (((xx // 1024 ) / 1024 ) * 256)
if any [((xx // 1024) < 55) ((xx // 1024) > 945 ) ] [slice: (to-integer (((yy // 1024 ) / 1024 ) * 256) )]
append display/effect/draw reduce ['image imgs/:slice xy1 xy2 ]
][
append display/effect/draw reduce [
'pen color
'fill-pen color
'box xy1 xy2
]
]
xy1/x: xy1/x + 4
xy2/x: xy2/x + 4
]
show display
]
;this function calculate the new position
player-move: function [/backwards ] [mul ] [
either backwards [ mul: -1 ] [mul: 1 ]
newpx: px - ((get-angles heading ) * stride * mul)
newpy: py - ((get-angle heading) * stride * mul)
c: to-integer (newpx / 1024)
l: to-integer (newpy / 1024)
if laby/:l/:c = 0 [
px: newpx
py: newpy
retrace
]
]
;this control when user press keyboard buttons
insert-event-func [
if (event/type = 'key) [
switch event/key [
up [ player-move ]
down [player-move/backwards ]
left [
heading: remainder (heading + (360 - turn)) 360
retrace
]
right [
heading: remainder (heading + turn) 360
retrace
]
]
]
event
]
retrace
view/title screen join "Raycaster " system/script/header/version
This is just a very simple example. This script can be optimized in many, many ways.
This post just show you can Rebol language can be applied or every task, it's so powerful and simple, that I consider it better than Java, C++, C#, etc.
No comments:
Post a Comment