News:

Building a 3D Ray Tracer  By stevmjon

Main Menu

Rebound loop

Started by RaverDave, January 21, 2006, 05:27:09 PM

Previous topic - Next topic

RaverDave

Ok, sorry I have marked it out clearer, the problem showing a rebound loop, this is showing now in red lines, where the ball would hit the brick at the top say, then the one to the right, bottom, hit side of screen, then top..and so forth! never breaking out of the diamond pattern!

Dunno if I will continue work on this,it has been harder than anticipated and I have needed hellp a little too much for even my liking! I am pleased with the editor and i guess it could become pretty generic for single screened levels!

Draco9898

#1
Your collision math is messed up, however you might have set that up.
It's hitting a brick, but can't determine which brick it hit, so it never gets rid of bricks, thus your ball is stuck inside these bricks.
Your collision code probably misses a region it should be checking...

Did you try adding the balls size on each side to the collision code?

Here's some working collision code, I hope this helps.

It'd probably be alot better just to cast a ray and bounce the ball off the bricks according to angle so it doesn't do weird stuff like bouncing off corners strangly.

; PROJECT : Breakout Help Code
; AUTHOR  : Draco
; CREATED : 1/21/2006
; EDITED  : 1/21/2006
; ---------------------------------------------------------------------
OpenScreen 640,480,16,0
Global ScreenW#=GetScreenWidth()
Global ScreenH#=GetScreenHeight()

Type tPlayerBall
X#, Y#
XVelo#, YVelo#
Radius#
EndType
Dim Playerb As tPlayerball
Playerb.Radius#=6
Playerb.X#=250
Playerb.Y#=250
Playerb.XVelo#=0.5
Playerb.YVelo#=0.5


`Brick Data
Type tBricks
X#, Y#, Sprite, DeadFlag
EndType
Dim Bricks(240) As tBricks
`create Brick image
Dim BrickImg(1): BrickImg(1)=GetFreeImage()
CreateImage BrickImg(1),40,20
RenderToImage BrickImg(1)
BoxC 0,0,40,20,1,RGB(99, 10, 10)
BoxC 2,2,38,18,1,RGB(199, 10, 10)
RenderToScreen
`Create Bricks
For X=1 To GetArrayElements(Bricks().tBricks,1)
`varibles
Bricks(X).X#=40*(X-1)
Bricks(X).Y#=100+Rnd(300)
`sprite
Bricks(X).Sprite=GetFreeSprite()
CreateSprite Bricks(X).Sprite
SpriteImage Bricks(X).Sprite,BrickImg(1)
PositionSprite Bricks(X).Sprite,Bricks(X).X#,Bricks(X).Y#
SpriteCollision Bricks(X).Sprite,1
SpriteCollisionMode Bricks(X).Sprite,0
Next X






Do
Cls 0
HandleBall()
HandleBricks()
Sync
Loop





Psub HandleBall()
`Draw
Circle Playerb.X#, Playerb.Y#,(Playerb.Radius#*2),0
`Physics
Playerb.X#=Playerb.X#+Playerb.XVelo#
Playerb.Y#=Playerb.Y#+Playerb.YVelo#
`Level boundries
If Playerb.X#+Playerb.Radius#>ScreenW#
 Playerb.X#=ScreenW#-Playerb.Radius#
 Playerb.XVelo#=Playerb.XVelo#*-1
EndIf
If Playerb.X#-Playerb.Radius#<0
 Playerb.X#=0+Playerb.Radius#
 Playerb.XVelo#=Playerb.XVelo#*-1
EndIf
 If Playerb.Y#+Playerb.Radius#>ScreenH#
 Playerb.Y#=ScreenH#-Playerb.Radius#
 Playerb.YVelo#=Playerb.YVelo#*-1
EndIf
If Playerb.Y#-Playerb.Radius#<0
 Playerb.Y#=0+Playerb.Radius#
 Playerb.YVelo#=Playerb.YVelo#*-1
EndIf  
EndPsub



Psub HandleBricks()
For X=1 To GetArrayElements(Bricks().tBricks,1)
 `Draw
 DrawSprite Bricks(X).Sprite
 `Collision
 If Bricks(X).DeadFlag=0
  X#=Playerb.X#-Playerb.Radius#
  Y#=Playerb.Y#-Playerb.Radius#
  X2#=Playerb.X#+Playerb.Radius#
  Y2#=Playerb.Y#+Playerb.Radius#
  CollisionFlag=RectHitSprite(X# ,Y# ,X2# ,Y2# ,Bricks(X).Sprite)
  If CollisionFlag=1
   `Hit Left
   If X#>GetSpriteX(Bricks(X).Sprite)
    Playerb.XVelo#=Playerb.XVelo#*-1
   EndIf
   `Hit Right
   If X2#<GetSpriteX(Bricks(X).Sprite)+GetSpriteWidth(Bricks(X).Sprite)
    Playerb.XVelo#=Playerb.XVelo#*-1
   EndIf
   `Hit Top
   If Y#>GetSpriteY(Bricks(X).Sprite)
    Playerb.YVelo#=Playerb.YVelo#*-1
   EndIf
   `Hit Bottom
   If Y2#<GetSpriteY(Bricks(X).Sprite)+GetSpriteHeight(Bricks(X).Sprite)
    Playerb.YVelo#=Playerb.YVelo#*-1
   EndIf
   Bricks(X).DeadFlag=1
   DeleteSprite Bricks(X).Sprite
  EndIf
 EndIf
Next X
EndPsub
DualCore Intel Core 2 processor @ 2.3 ghz, Geforce 8600 GT (latest forceware drivers), 2 gigs of ram, WIN XP home edition sp2, FireFox 2.

"You'll no doubt be horrified to discover that PlayBasic is a Programming Language." -Kevin

kevin

The  problem is caused by the impacts with the 'unbreakable' tiles    Since the balls direction is reflected (and not altered) and the tiles aren't removed upon impact.  Then once the ball enters a section, it can certainly get caught rebounding within a particular block layout.  


Possible Solution(s),

 * Alter the reflected angle of the ball upon impact with these tiles.  If you turn it slightly at the point of impact (plus or minus 1 degree), the user
won't really notice and the ball won't always follow the same path.  

 * change the tile layout in the levels (it will certainly occur in more than one)

 * change the block width/heights or the ball size.      

 * don't have totally indestructible tiles, or apply an impact counter.  So after X number of impacts the block can be destroyed.

kevin

#3
This example demos both the problem and the cheesy solution to 'kick' the ball off it's perfect path.

When the demo starts you'll notice that the ball rebounds perfectly and thus will constantly travel over the same pixels.  This is caused as the region it has to reboud within is square.

 Press the space bar to toggel between perfect reflect (flipping the speeds) and randomly tweaking the the angle of the ball.  



PlayBASIC Code: [Select]
   ScreenWidth=200
ScreenHeight=200

; Example of perfect rebound prob
type tBall
xpos#,ypos#
angle#
speed#
XSpeed#,Yspeed#
endtype

Dim Ball as tball
; init ball

Ball.xpos=ScreenWidth/4
Ball.ypos=ScreenHeight/2
ball.speed=2
ball.angle#=45
ball.xspeed=cos(ball.angle)*Ball.speed
ball.yspeed=Sin(ball.angle)*Ball.speed

Radius=5


BallScreen=newimage(ScreenWidth,ScreenHeight)


Do
Cls 0
rendertoimage BallScreen

boxc 0,0,ScreenWidth,ScreenHeight-1,0,rgb(0,0,255)

x#=Ball.xpos+Ball.Xspeed
y#=Ball.ypos+Ball.yspeed

if x#<radius
x#=radius
Ball.Xspeed=Ball.Xspeed*-1
NewDirection(Rebounds)
endif

if x#>ScreenWidth
x#=ScreenWidth-radius
Ball.Xspeed=Ball.Xspeed*-1
NewDirection(Rebounds)
endif

if y#<radius
y#=radius
Ball.Yspeed=Ball.Yspeed*-1
NewDirection(Rebounds)
endif

if Y#>ScreenHeight
Y#=ScreenHeight-radius
Ball.Yspeed=Ball.yspeed*-1
NewDirection(Rebounds)
endif

Ball.xpos=x#
Ball.ypos=y#

Circle x#,y#,5,true
RenderToScreen

cx=getscreenwidth()/2 -(GetImageWidth(BallScreen)/2)
cy=getscreenHeight()/2 -(GetImageHeight(BallScreen)/2)

DrawImage BallScreen,cx,cy,0

CircleC cx+x#,cy+y#,5,true,rgb (255,0,0)



print "Ball State"
print "Xpos "+str$(Ball.xpos)
print "Ypos "+str$(Ball.ypos)
print "Angle "+str$(Ball.angle)

print ""

if Rebounds=false
m$="Perfect Reflect"
else
m$="Randomly Alter Rebound Direction"
endif
print "Rebound State:"+m$

if spacekey() and keypressed=false
Rebounds=1-Rebounds
keypressed=true
endif

if scancode()=0 then KeyPressed=False


centertext getscreenwidth()/2,getscreenheight()-50,"Press Space to Toggle Rebound Modes"
Sync
loop



Function NewDirection(ForceChangeOFDir)
sx#=ball.Xspeed
sy#=ball.Yspeed
angle#=getangle2d(0,0,sx#,sy#)

if ForceChangeOFDir=true
; randomyl vary the rebound direction.
angle#=wrapangle(angle#,rndrange(-1,1))
ball.xspeed=cos(ball.angle)*Ball.speed
ball.yspeed=Sin(ball.angle)*Ball.speed
endif
ball.angle#=angle#

EndFunction






RaverDave

#4
Yes,this demonstrates the problem perfectly, and the solution works! I didnt have to have indestructible bricks, but I just thought it made for more level variations! Adds to the overall gameplay aswell, impact counters are added already, I put them in a week ago or so, its all part of the editor/engine! Basically in the Level editor I can set any tile to any value from 1-10! 10 being indestructible, when the level is loaded into the game engine,if the value is a 10 then its ignored as part of the brick count! But of course is still in the rebound part! My next task(which will be fun) is to add bricks that move, But I have ideas about that so should be easy to do **ahem**