Created
February 24, 2018 15:30
-
-
Save SpaceVoyager/49054b61135eee26bd6a2b912f3f5ca3 to your computer and use it in GitHub Desktop.
raycast.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# RayCast | |
# Simple raycasting based renderer | |
# Touch the left part to rotate, and touch the right part to move forward | |
# Coded in a few hours during my holidays, July 2014, straight from my iPhone - thanks Pythonista !!! | |
# Feel free to upgrade ! | |
# Enjoy ! | |
# Emmanuel ICART | |
# [email protected] | |
from scene import * | |
from math import * | |
# rendering step - 1=best(slower) | |
RENDERING_STEP=2 | |
# level data | |
# 1 = wall, 0 = empty | |
level = [[1,1,1,1,1,1,1,1], | |
[1,1,0,0,0,0,0,1], | |
[1,0,0,0,0,1,0,1], | |
[1,0,1,0,0,0,0,1], | |
[1,1,0,0,0,1,0,1], | |
[1,0,0,1,1,0,0,1], | |
[1,0,0,0,0,0,0,1], | |
[1,1,1,1,1,1,1,1]] | |
LX=len(level[0]) | |
LZ=len(level) | |
CellSize=128 | |
scan=10 | |
# player | |
xo=CellSize*LX/2 | |
zo=CellSize*LZ/2 | |
angle=45.0 | |
fov=80 | |
class RayCastScene (Scene): | |
def setup(self): | |
# preload the texture | |
self.texture='PC_Chest_Closed' | |
self.screenWidth=int(self.size.w) | |
self.screenHeight=int(self.size.h) | |
self.xTouchStart=0 | |
self.yTouchStart=0 | |
load_image(self.texture) | |
pass | |
def draw(self): | |
global angle | |
global xo | |
global zo | |
# This will be called for every frame (typically 60 times per second). | |
# clear background | |
background(0, 0, 0) | |
focale=0.5*self.screenWidth/tan(radians(fov/2)) | |
# compute each screen column | |
for column in xrange(0,self.screenWidth,RENDERING_STEP): | |
scan_angle=angle+((float(column)-self.screenWidth/2)*fov)/self.screenWidth | |
c=cos(radians(scan_angle)) | |
s=sin(radians(scan_angle)) | |
if abs(c)<0.001: | |
if c>0: | |
c=0.001 | |
else: | |
c=-0.001 | |
if abs(s)<0.001: | |
if s>0: | |
s=0.001 | |
else: | |
s=-0.001 | |
t2=s/c | |
t1=c/s | |
ok1=True | |
ok2=True | |
#Initialization of ray casting | |
pz1=t2*CellSize | |
if c>0: | |
px1=CellSize | |
ini=0 | |
else: | |
px1=-CellSize | |
pz1=-pz1 | |
ini=CellSize-1 | |
xp1=ini+(((int)(xo/CellSize))*CellSize) | |
zp1=zo+((xp1-xo)*pz1)/px1 | |
px2=t1*CellSize | |
if s>0: | |
pz2=CellSize | |
ini=0 | |
else: | |
pz2=-CellSize | |
px2=-px2 | |
ini=CellSize-1 | |
zp2=ini+(((int)(zo/CellSize))*CellSize) | |
xp2=xo+((zp2-zo)*px2)/pz2 | |
#****** cast a ray for z walls ****** | |
compteur=0 | |
while True: | |
xp1+=px1 | |
zp1+=pz1 | |
compteur+=1 | |
xd=(int)(xp1/CellSize) % LX | |
zd=(int)(zp1/CellSize) % LZ | |
if (xd<0): xd=0 | |
if (zd<0): zd=0 | |
if level[xd][zd]!=0 or compteur>=scan: break | |
if (compteur==scan):ok1=False | |
distance1=(xp1-xo)/c | |
col1=(zp1 % CellSize) | |
if (px1<=0): col1=CellSize-1-col1 | |
#****** cast a ray for x walls ****** | |
compteur=0 | |
while True: | |
xp2+=px2 | |
zp2+=pz2 | |
compteur+=1 | |
xd=(int)(xp2/CellSize) % LX | |
zd=(int)(zp2/CellSize) % LZ | |
if (xd<0):xd=0 | |
if (zd<0):zd=0 | |
if level[xd][zd]!=0 or compteur>=scan: break | |
if (compteur==scan): ok2=False | |
distance2=(zp2-zo)/s | |
col2=(xp2 % CellSize) | |
if (pz2>=0):col2=CellSize-1-col2 | |
#Choose the nearest wall (x or z) | |
if (distance1<distance2): | |
distance=1+(distance1) | |
colonne=col1 | |
else: | |
distance=1+(distance2) | |
colonne=col2 | |
if ok1 or ok2: | |
# fix the fishbowl effect | |
distance=distance*cos(radians(angle-scan_angle)) | |
#compute the wall screen height | |
hauteur = ((CellSize*focale)/distance) | |
# draw the column | |
ximage=(colonne*128)/CellSize # 101 x 171 tile | |
image(self.texture,column,(self.screenHeight-hauteur)/2,RENDERING_STEP,hauteur,ximage,0,RENDERING_STEP,171) | |
# display fingers | |
fill(1, 0, 0) | |
for touch in self.touches.values(): | |
ellipse(touch.location.x - 50, touch.location.y - 50, 100, 100) | |
# rotation control | |
if (touch.location.x<self.screenWidth/2): | |
angle += 0.04*(touch.location.x-self.xTouchStart) | |
else: | |
# displacement control | |
speed=(touch.location.y-self.yTouchStart)*0.2 | |
dx=speed*cos(radians(angle)) | |
dz=speed*sin(radians(angle)) | |
if level[int((xo+dx)/CellSize)][int(zo/CellSize)]!=0:dx=0 | |
if level[int(xo/CellSize)][int((zo+dz)/CellSize)]!=0:dz=0 | |
xo+=dx | |
zo+=dz | |
def touch_began(self, touch): | |
global angle | |
self.angleStart=angle | |
if touch.location.x<self.screenWidth/2: | |
self.xTouchStart=touch.location.x | |
else: | |
self.yTouchStart=touch.location.y | |
pass | |
def touch_moved(self, touch): | |
pass | |
def touch_ended(self, touch): | |
pass | |
run(RayCastScene(),LANDSCAPE) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment