Quote: "You could also simply make an large collision box around the enemys"
Na that won't cut it either.
Think about this scenario:
The blue cross represents the player, the green line represents the sprite and the red cross represents the centre of the sprite.
The sprite is nowhere near a wall but the player should still be able to see part of the green line.
But with the current method I'd be using to determine if there's something in the way of the sprite it'd be testing a line between the blue and red crosses. So in this picture, the sprite wouldn't be shown but should be being shown.
I also recreated the whole code in DBP.
Here's the code from Java:
package imbad;
import org.newdawn.slick.*;
import java.io.*;
import java.awt.Font;
/**
* @author Cowbox
*/
public class Game extends BasicGame
{
// Declaration
Image tileimgs[]=new Image[64];
Image overlay,background;
private int px,py,mapno;
public static int screenwidth,screenheight;
private double realx,realy,angle,crouch,speed;
private String[][] map=new String[19][19];
private String OS;
private int playmusic;
private int[][] bsp=new int[608][608];
TrueTypeFont trueTypeFont=null;
Sound music;
// Constructor
public Game(String title)
{
super(title);
// Set some initial variables
px=3;py=3;
realx=(px*32)+16;realy=(py*32)+16;
screenwidth=640;screenheight=480;
angle=180f;
playmusic=1;
// Load the first map
mapno=1;
loadmap(mapno);
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws SlickException
{
AppGameContainer app=new AppGameContainer(new Game("I. M. Bad"));
app.setDisplayMode(screenwidth,screenheight,false);
app.setSmoothDeltas(true);
app.setTargetFrameRate(66);
app.setShowFPS(false);
app.start();
}
// Initialization
public void init(GameContainer gc) throws SlickException
{
tileimgs[0]=new Image("data/images/tile0.png");
tileimgs[1]=new Image("data/images/tile1.png");
overlay=new Image("data/images/overlay.png");
background=new Image("data/images/background.png");
music=new Sound("data/music/IMCool.ogg");
Font font=new Font("Verdana",Font.PLAIN,12);
trueTypeFont=new TrueTypeFont(font,true);
music.play(1,0.1f);
}
// Update the gamestate
public void update(GameContainer gc,int delta) throws SlickException
{
keyInput(gc,delta);
}
// Update the game screen
public void render(GameContainer gc,Graphics g) throws SlickException
{
handle3D();
handle2D();
//trueTypeFont.drawString(0,0,"FPS: "+Integer.toString(app.getFPS()),Color.white);
trueTypeFont.drawString(0,16,"X,Y: "+Integer.toString((int)realx)+","+Integer.toString((int)realy),Color.white);
trueTypeFont.drawString(0,32,"Angle: "+Integer.toString((int)angle),Color.white);
}
// Handle the 3D viewport
private void handle3D()
{
double tilescale;
background.draw(0,0,640,480);
for(double exang=-30;exang<30;exang+=0.2)
{
tilescale=512/rayCastAng((int)realx,(int)realy,angle+exang);
tileimgs[1].draw((screenwidth/2)-(int)(exang*10),(screenheight/2)-(int)(tilescale*10*crouch),2,(int)(tilescale*20),new Color((int)(tilescale*16),(int)(tilescale*16),(int)(tilescale*16),255));
}
}
// Handle the 2D overlay
private void handle2D()
{
overlay.draw(0,0,640,480);
}
private void keyInput(GameContainer gc,int delta)
{
Input input=gc.getInput();
crouch=1f;
speed=2f;
if(input.isKeyDown(Input.KEY_LCONTROL))
{
crouch=1.5f;
speed=1f;
}
if(input.isKeyDown(Input.KEY_UP)||input.isKeyDown(Input.KEY_W))
{
double mx=speed*Math.sin(Math.toRadians(angle));
double my=speed*Math.cos(Math.toRadians(angle));
if(bsp[(int)(realx+mx)][(int)(realy+my)]==0)
{
realx+=mx;
realy+=my;
}
}
if(input.isKeyDown(Input.KEY_DOWN)||input.isKeyDown(Input.KEY_S))
{
double mx=-speed*Math.sin(Math.toRadians(angle));
double my=-speed*Math.cos(Math.toRadians(angle));
if(bsp[(int)(realx+mx)][(int)(realy+my)]==0)
{
realx+=mx;
realy+=my;
}
}
if(input.isKeyDown(Input.KEY_A))
{
double mx=speed*Math.sin(Math.toRadians(angle+90));
double my=speed*Math.cos(Math.toRadians(angle+90));
if(bsp[(int)(realx+mx)][(int)(realy+my)]==0)
{
realx+=mx;
realy+=my;
}
}
if(input.isKeyDown(Input.KEY_D))
{
double mx=speed*Math.sin(Math.toRadians(angle-90));
double my=speed*Math.cos(Math.toRadians(angle-90));
if(bsp[(int)(realx+mx)][(int)(realy+my)]==0)
{
realx+=mx;
realy+=my;
}
}
if(input.isKeyDown(Input.KEY_LEFT))
{
angle+=speed;
if(angle>360f)
{
angle=0f;
}
}
if(input.isKeyDown(Input.KEY_RIGHT))
{
angle-=speed;
if(angle<0f)
{
angle=360f;
}
}
if(input.isKeyDown(Input.KEY_ESCAPE))
{
System.exit(0);
}
if(input.isKeyDown(Input.KEY_F1))
{
music.stop();
}
}
// Cast a ray based on a start point and an angle
private double rayCastAng(int rx,int ry,double angle)
{
double dx=Math.sin(Math.toRadians(angle));
double dy=Math.cos(Math.toRadians(angle));
double ray;
for(ray=0;ray<1024;ray+=0.1)
{
if(bsp[(int)(rx+(ray*dx))][(int)(ry+(ray*dy))]==1)
{
break;
}
}
return ray;
}
// Load the map text file into map[][]
private void loadmap(int mapnum)
{
// Declare local variables
String str;
int tx,ty;
File file;
// Check some system stuff (not that it works)
OS=System.getProperty("os.name");
if(OS.equalsIgnoreCase("linux"))
{
file=new File("./data/maps/map"+Integer.toString(mapnum)+".map");
}
else
{
file=new File("data/maps/map"+Integer.toString(mapnum)+".map");
}
// Set up some input streamy things
FileInputStream fis=null;
BufferedInputStream bis=null;
DataInputStream dis=null;
// Try and read the file
try
{
// Read the fle
fis=new FileInputStream(file);
bis=new BufferedInputStream(fis);
dis=new DataInputStream(bis);
// Runthrough the array while reading the file
for(ty=0;ty<19;ty++)
{
if(dis.available()!=0)
{
// Read each line
str=dis.readLine();
for(tx=0;tx<19;tx++)
{
// Deconstruct each line and put each character in the array
char c=str.charAt(tx);
map[tx][ty]=Character.toString(c);
if(Integer.decode(map[tx][ty])==1)
{
for(int ttx=0;ttx<32;ttx++)
{
for(int tty=0;tty<32;tty++)
{
bsp[(tx*32)+ttx][(ty*32)+tty]=1;
}
}
}
if(Integer.decode(map[tx][ty])==3)
{
bsp[(tx*32)+16][(ty*32)+16]=3;
}
}
}
}
// Close the input streams
fis.close();
bis.close();
dis.close();
}
// Catch failures
catch(FileNotFoundException e)
{e.printStackTrace();}
// Catch failures
catch(IOException e)
{e.printStackTrace();}
}
}
And here's what it looks like in DBP:
// Project: IMBad
// Created: Tuesday, March 29, 2011
// Declare arrays
dim map$(19,19)
dim bsp(608,608)
// Application flow
gosub Game
gosub main
gosub init
do
gosub update
gosub rendera
if quit=1 then exit
loop
end
// Constructor
Game:
px=3
py=3
realx#=(px*32)+16
realy#=(py*32)+16
screenwidth=640
screenheight=480
angle#=180
mapno=1
loadmap(mapno)
return
// main method
main:
set window title "I. M. Bad"
set display mode screenwidth,screenheight,32,0
sync on
sync rate 66
return
// Initialization
init:
load image "data/images/tile0.png",1,1
load image "data/images/tile1.png",2,1
load image "data/images/overlay.png",3
load image "data/images/background.png",4,1
load sound "data/music/IMCool.ogg",1
set text font "Verdana"
set text size 12
play sound 1
sprite 1,screenwidth,screenheight,1
return
// Update the gamestate
update:
gosub keyInput
return
// Update the game screen
rendera:
gosub handle3D
gosub handle2D
text 0,0,"FPS: "+str$(screen fps())
text 0,16,"X,Y: "+str$(realx#)+","+str$(realy#)
text 0,32,"Angle: "+str$(angle#)
sync
return
handle3D:
set sprite image 1,4
size sprite 1,screenwidth,screenheight
paste sprite 1,0,0
for exang#=-30 to 30 step 0.2
tilescale#=512.0/rayCastAng(int(realx#),int(realy#),angle#+exang#)
set sprite image 1,2
size sprite 1,2,int(tilescale#*20)
set sprite diffuse 1,tobyte(tilescale#*16),tobyte(tilescale#*16),tobyte(tilescale#*16)
paste sprite 1,(screenwidth/2)-int(exang#*10),(screenheight/2)-int(tilescale#*10*crouch#)
next exang#
set sprite diffuse 1,255,255,255
return
handle2D:
set sprite image 1,3
size sprite 1,screenwidth,screenheight
paste sprite 1,0,0
return
keyInput:
crouch#=1
speed#=2
if keystate(29)
crouch#=1.5
speed=1
endif
if keystate(200) || keystate(17)
mx#=speed#*sin(angle#)
my#=speed#*cos(angle#)
if bsp(int(realx#+mx#),int(realy#+my#))=0
realx#=realx#+mx#
realy#=realy#+my#
endif
endif
if keystate(208) || keystate(31)
mx#=-speed#*sin(angle#)
my#=-speed#*cos(angle#)
if bsp(int(realx#+mx#),int(realy#+my#))=0
realx#=realx#+mx#
realy#=realy#+my#
endif
endif
if keystate(30)
mx#=speed#*sin(angle#+90)
my#=speed#*cos(angle#+90)
if bsp(int(realx#+mx#),int(realy#+my#))=0
realx#=realx#+mx#
realy#=realy#+my#
endif
endif
if keystate(32)
mx#=speed#*sin(angle#-90)
my#=speed#*cos(angle#-90)
if bsp(int(realx#+mx#),int(realy#+my#))=0
realx#=realx#+mx#
realy#=realy#+my#
endif
endif
if keystate(203)
angle#=wrapvalue(angle#+speed#)
endif
if keystate(205)
angle#=wrapvalue(angle#-speed#)
endif
if keystate(1)
quit=1
endif
if keystate(59)
stop sound 1
endif
return
function rayCastAng(rx,ry,angle#)
dx#=sin(angle#)
dy#=cos(angle#)
for ray#=0 to 1024 step 0.1
if bsp(int(rx+(ray#*dx#)),int(ry+(ray#*dy#)))=1
exit
endif
next ray#
endfunction ray#
function loadmap(mapnum)
open to read 1,"data/maps/map"+str$(mapnum)+".map"
for ty=0 to 19
read string 1,line$
for tx=1 to len(line$)
map$(tx-1,ty)=mid$(line$,tx)
next tx
next ty
for tx=0 to 19
for ty=0 to 19
if map$(tx,ty)="1"
for ttx=0 to 32 step 1
for tty=0 to 32 step 1
bsp((tx*32)+ttx,(ty*32)+tty)=1
next tty
next ttx
endif
if map$(tx,ty)="3"
bsp((tx*32)+16,(ty*32)+16)=3
endif
next ty
next tx
close file 1
endfunction
function tobyte(value)
if value<0 then value=0
if value>255 then value=255
endfunction value
In Java I can easily get it up to 500FPS, but in DBP it can barely reach 60FPS most of the time for me.