I insist about the importance of this.
Execute this example code and input firstly "1" for the 2 requests. Then ESCape and try again with max values for the 2 requests (switch off debugger).
Code: Select all
; This example shows the way to make a "elastic perfectly collision" between 2 spheric (with masses
;centre same as geometrical centre) objects in the emptyness (no rub).
;Elastic perfectly collision in a closed system (closed system means no external forces but only the
;two ones of the both colliding objects forces) mean no lossing kinetic energy from the closed system.
;It is ideal, because in reality there is always a kinetic energy lossing in rub, deformation, rotation,
;heat, etc.
; NOTE: decrease #lines constant and/or number of objects if your computer is too slow.
; NOTE2: you can add external forces (like gravities between objects, or absolute to all)
;playing with dirX and dirY parameters.
; 2003-12-25 (Psychophanta)
;-INITS:
#PI=3.14159265
bitplanes.b=32:RX.w=1024:RY.w=768
If InitMouse()=0 Or InitSprite()=0 Or InitSprite3D()=0 Or InitKeyboard()=0
MessageRequester("Error","Can't open DirectX",0)
End
EndIf
Structure balls
sprite.w;<-#Sprite
x.f:y.f;<-coordenadas instantáneas
dirX.f:dirY.f;<-Vector director
HalfWidth.w:HalfHeight.w;<-centro geométrico
Dimension.w
Mass.f;<-masa
Kinetic.f;<-energÃa cinética
EndStructure
NewList Capsule.balls():Cursor.balls
;-FUNCTIONS:
Procedure Shock0(*a.balls)
;*;al momento de chocar tenemos:
;ENTRADAS: Vectores directores de los movimientos ((dirX,dirY) para Objeto0 y (dirX,dirY) para Objeto1)
; Masas de Objeto1 y de Objeto0 (Objeto0 Mass y Objeto1 Mass)
;*;Debemos calcular:
;SALIDAS: Nuevo vector director de los movimientos de Objeto1 y de Objeto0 ((dirX,dirY) de Objeto0 y (dirX,dirY) de Objeto1).
;*;CANTIDADES DE MOVIMIENTO:
; MQBallX.f=Capsule()\dirX*Capsule()\Mass:MQBallY.f=Capsule()\dirY*Capsule()\Mass;<-cantidad de movimiento de Ball
; MQCursorX.f=*a\dirX**a\Mass:MQCursorY.f=*a\dirY**a\Mass;<-cantidad de movimiento de Cursor
; MQBall.f=Sqr(MQBallX.f*MQBallX.f+MQBallY.f*MQBallY.f)
; MQCursor.f=Sqr(MQCursorX.f*MQCursorX.f+MQCursorY.f*MQCursorY.f)
;*;ENERGIAS CINETICAS:
;*a\Kinetic=(Pow(*a\dirX,2)+Pow(*a\dirY,2))**a\Mass/2;<-(m/2)*v^2 de Objeto0
;Capsule()\Kinetic=(Pow(Capsule()\dirX,2)+Pow(Capsule()\dirY,2))*Capsule()\Mass/2;<-(m/2)*v^2 de Objeto1
;*;COMPONENTES POR CONTACTO:
;Es un vector que está en la lÃnea de choque (recta normal a la recta tangente, en el punto de contacto, sobre la superficie contra la que se choca).
;Obtenemos su sentido y dirección, que viene marcado por la diferencia de coordenadas de cada objeto al momento de chocar:
DiffX.f=Capsule()\x-*a\x:DiffY.f=Capsule()\y-*a\y;<-rectángulo que forman las posiciones de los colisionantes
Distance.f=Sqr(DiffX*DiffX+DiffY*DiffY)
;A continuación, su módulo, que depende de la de las cantidades de movimiento de ambos cuerpos:
;ModuloObjeto1.f=Sqr(1+Pow(*a\Mass/Capsule()\Mass,2));<-Módulo de la componente por contacto de Objeto1.
;ModuloObjeto0.f=Sqr(1+Pow(Capsule()\Mass/*a\Mass,2));<-Módulo de la componente por contacto de Objeto0.
ModuloObjeto1.f=*a\Mass/(*a\Mass+Capsule()\Mass)
ModuloObjeto0.f=Capsule()\Mass/(*a\Mass+Capsule()\Mass)
;Probar con:
;ModuloObjeto1.f=*a\Kinetic/(*a\Kinetic+Capsule()\Kinetic)
;ModuloObjeto0.f=Capsule()\Kinetic/(*a\Kinetic+Capsule()\Kinetic)
;y con:
;ModuloObjeto1.f=*a\Kinetic/Sqr(Pow(*a\Kinetic,2)+Pow(Capsule()\Kinetic,2))
;ModuloObjeto0.f=Capsule()\Kinetic/Sqr(Pow(*a\Kinetic,2)+Pow(Capsule()\Kinetic,2))
;y con:
;ModuloObjeto1.f=Sqr(Capsule()\Kinetic+*a\Kinetic)/2
;ModuloObjeto0.f=Sqr(Capsule()\Kinetic+*a\Kinetic)/2
;*;Calcular las COMPONENTES POR CONTACTO (un vector normal a la tangente
;en el punto de contacto con la superficie contra la que se choca); que tendrán sus módulo dados,
;añadiendo dichas componentes a las componentes de los vectores directores de los movimientos
;de Objeto0 y Objeto1
Capsule()\dirX+DiffX*ModuloObjeto1/Distance.f
Capsule()\dirY+DiffY*ModuloObjeto1/Distance.f
*a\dirX-DiffX*ModuloObjeto0/Distance.f
*a\dirY-DiffY*ModuloObjeto0/Distance.f
;*;Preservar distancia:
Clip.f=(*a\Dimension/2+Capsule()\Dimension/2)-Distance.f
If Clip.f>0:Clip.f/2
Capsule()\x+DiffX.f*Clip.f/Distance.f
Capsule()\y+DiffY.f*Clip.f/Distance.f
*a\x-DiffX.f*Clip.f/Distance.f
*a\y-DiffY.f*Clip.f/Distance.f
EndIf
EndProcedure
Procedure Shock(*a.balls)
;*;al momento de chocar tenemos:
;ENTRADAS: Vectores directores de los movimientos ((dirX,dirY) para Objeto0 y (dirX,dirY) para Objeto1)
; Masas de Objeto1 y de Objeto0 (Objeto0 Mass y Objeto1 Mass)
;*;Debemos calcular:
;SALIDAS: Nuevo vector director de los movimientos de Objeto1 y de Objeto0 ((dirX,dirY) de Objeto0 y (dirX,dirY) de Objeto1).
;*;CANTIDADES DE MOVIMIENTO:
; MQBallX.f=Capsule()\dirX*Capsule()\Mass:MQBallY.f=Capsule()\dirY*Capsule()\Mass;<-cantidad de movimiento de Ball
; MQCursorX.f=*a\dirX**a\Mass:MQCursorY.f=*a\dirY**a\Mass;<-cantidad de movimiento de Cursor
; MQBall.f=Sqr(MQBallX.f*MQBallX.f+MQBallY.f*MQBallY.f)
; MQCursor.f=Sqr(MQCursorX.f*MQCursorX.f+MQCursorY.f*MQCursorY.f)
;*;ENERGIAS CINETICAS:
;*a\Kinetic=(Pow(*a\dirX,2)+Pow(*a\dirY,2))**a\Mass/2;<-(m/2)*v^2 de Objeto0
;Capsule()\Kinetic=(Pow(Capsule()\dirX,2)+Pow(Capsule()\dirY,2))*Capsule()\Mass/2;<-(m/2)*v^2 de Objeto1
;*;COMPONENTES POR CONTACTO:
;Es un vector que está en la lÃnea de choque (recta normal a la recta tangente, en el punto de contacto, sobre la superficie contra la que se choca).
;Obtenemos su sentido y dirección, que viene marcado por la diferencia de coordenadas de cada objeto al momento de chocar:
DiffX.f=Capsule()\x-*a\x:DiffY.f=Capsule()\y-*a\y;<-Vector de distancia
;su módulo depende de la componente de la velocidad con respecto a la linea de choque (DiffX,DiffY) (proyección del vector (dirX,dirY) sobre el (DiffX,DiffY)):
K.f=(DiffX.f**a\dirX+DiffY.f**a\dirY)/(DiffX.f*DiffX.f+DiffY.f*DiffY.f);<-constante de proyección del actual vector del movimiento de Cursor sobre la lÃnea de choque.
dirCursorXK.f=K.f*DiffX.f:dirCursorYK.f=K.f*DiffY.f;<-vector componente en lÃnea de choque de la velocidad de Cursor.
K.f=(-DiffX.f*Capsule()\dirX-DiffY.f*Capsule()\dirY)/(-DiffX.f*-DiffX.f+-DiffY.f*-DiffY.f);<-constante de proyección del actual vector del movimiento de Ball sobre la lÃnea de choque.
dirBallXK.f=K.f*-DiffX.f:dirBallYK.f=K.f*-DiffY.f;<-vector componente en lÃnea de choque de la velocidad de Ball.
CX.f=(2*Capsule()\Mass*dirBallXK.f+*a\Mass*dirCursorXK.f-Capsule()\Mass*dirCursorXK.f)/(*a\Mass+Capsule()\Mass)
CY.f=(2*Capsule()\Mass*dirBallYK.f+*a\Mass*dirCursorYK.f-Capsule()\Mass*dirCursorYK.f)/(*a\Mass+Capsule()\Mass)
BX.f=(2**a\Mass*dirCursorXK.f+Capsule()\Mass*dirBallXK.f-*a\Mass*dirBallXK.f)/(*a\Mass+Capsule()\Mass)
BY.f=(2**a\Mass*dirCursorYK.f+Capsule()\Mass*dirBallYK.f-*a\Mass*dirBallYK.f)/(*a\Mass+Capsule()\Mass)
;*;Ahora obtener el vector resultante para el movimiento de Ball:
;Se mantiene la componente perpendicular a la linea de choque del movimiento de Ball (componente que no afecta al choque):
Capsule()\dirX-dirBallXK.f+BX.f:Capsule()\dirY-dirBallYK.f+BY.f;<-se suman, obteniendo el vector buscado.
;*;Finalmente obtener el vector director resultante para el movimiento de Cursor:
;Se mantiene la componente perpendicular a la linea de choque del movimiento de Cursor (componente que no afecta al choque):
*a\dirX-dirCursorXK.f+CX.f:*a\dirY-dirCursorYK.f+CY.f;<-se suman, obteniendo el vector buscado.
;*;Preservar distancia:
Distance.f=Sqr(DiffX*DiffX+DiffY*DiffY)
Clip.f=(*a\Dimension/2+Capsule()\Dimension/2)-Distance.f
If Clip.f>0:Clip.f/2
Capsule()\x+DiffX.f*Clip.f/Distance.f
Capsule()\y+DiffY.f*Clip.f/Distance.f
*a\x-DiffX.f*Clip.f/Distance.f
*a\y-DiffY.f*Clip.f/Distance.f
EndIf
EndProcedure
Procedure CreateBallSprite(c.l,size.l,color.l)
CreateSprite(c,size,size,#PB_Sprite_Texture)
StartDrawing(SpriteOutput(c))
BackColor(0,0,0):R.w=color&$FF:G.w=color>>8&$FF:B.w=color>>16&$FF
For t.l=size/2 To 1 Step -1
R+160/size:G+160/size:B+160/size:If R>255:R=255:EndIf:If G>255:G=255:EndIf:If B>255:B=255:EndIf
Circle(size/2,size/2,t,RGB(R,G,B))
Next
StopDrawing()
EndProcedure
;-MOREINITS:
BallsDiameter.l=76;Val(InputRequester("Input","Please input 2D spheres diameter in #pixels (max. "+Str(RX.w/3)+")",Str(76)))
Lines.l=Val(InputRequester("Input","Please input number of lines of 2D spheres (max. "+Str(RY.w/BallsDiameter.l)+")",Str(2)))
BallsPerLine.l=Val(InputRequester("Input","Please input number of 2D spheres per line (max. "+Str(RX.w/BallsDiameter.l)+")",Str(RX.w/BallsDiameter.l-1)));<-Número de Objeto1 por lineas
While OpenScreen(RX.w,RY.w,bitplanes.b,"Balls")=0
If bitplanes.b>16:bitplanes.b-8
ElseIf RY.w>600:RX.w=800:RY.w=600
ElseIf RY.w>480:RX.w=640:RY.w=480
ElseIf RY.w>400:RX.w=640:RY.w=400
ElseIf RY.w>240:RX.w=320:RY.w=240
ElseIf RY.w>200:RX.w=320:RY.w=200
Else:MessageRequester("VGA limitation","Can't open Screen!",0):End
EndIf
Wend
Cursor\sprite=0
CreateBallSprite(Cursor\sprite,64,$009eae)
CreateSprite3D(Cursor\sprite,Cursor\sprite):ZoomSprite3D(Cursor\sprite,64,64)
Cursor\HalfWidth=SpriteWidth(Cursor\sprite)/2:Cursor\HalfHeight=SpriteHeight(Cursor\sprite)/2;<-centro de Objeto0
Cursor\Dimension=(SpriteWidth(Cursor\sprite)+SpriteHeight(Cursor\sprite))/2
Cursor\Mass=4*#PI*Pow(Cursor\Dimension/2,3)/3;<-masa de Objeto0
For g.b=1 To Lines.l
For t.w=1 To BallsPerLine.l
AddElement(Capsule())
Capsule()\sprite=t
CreateBallSprite(Capsule()\sprite,BallsDiameter.l,$6dae00)
CreateSprite3D(Capsule()\sprite,Capsule()\sprite):ZoomSprite3D(Capsule()\sprite,BallsDiameter.l,BallsDiameter.l)
Capsule()\HalfWidth=SpriteWidth(Capsule()\sprite)/2:Capsule()\HalfHeight=SpriteHeight(Capsule()\sprite)/2;<-centro de Objeto1
Capsule()\Dimension=(SpriteWidth(Capsule()\sprite)+SpriteHeight(Capsule()\sprite))/2
Capsule()\Mass=4*#PI*Pow(Capsule()\Dimension/2,3)/3;<-masa de Objeto1
Capsule()\x=t.w*BallsDiameter.l-Capsule()\HalfWidth+((RX.w-BallsDiameter.l*BallsPerLine.l)/2);<-Posición inicial X
Capsule()\y=g.b*BallsDiameter.l-Capsule()\HalfHeight;<-Posición inicial Y
Next
Next
mouseX=RX.w/2:mouseY=RY.w*4/5
Cursor\x=mouseX:Cursor\y=mouseY
MouseLocate(mouseX,mouseY);<-Posición inicial de Objeto0
Cursor\dirX=Random(1000000)/100000-5:Cursor\dirY=-Random(4000000)/1000000-1
;-MAIN:
Repeat
ExamineKeyboard()
ExamineMouse()
ClearScreen(0,0,0)
; Cursor position and vector:
prevmouseX=mouseX:prevmouseY=mouseY;<-previous mouse coordinates
mouseX=MouseX():mouseY=MouseY();<-current mouse coordinates
If mouseX<>prevmouseX Or mouseY<>prevmouseY;If mouse is moved:
Cursor\dirX=mouseX-prevmouseX:Cursor\dirY=mouseY-prevmouseY;<-vector director del movimiento de Cursor
mouseX=Cursor\x+Cursor\dirX:mouseY=Cursor\y+Cursor\dirY;<-actualizamos las coordenadas del mouse
MouseLocate(mouseX,mouseY);<-y reposicionamos el mouse en las actuales coordenadas de Cursor
EndIf
Cursor\x+Cursor\dirX:Cursor\y+Cursor\dirY;<-que son estas (se suma el vector director a las anteriores)
; Cursor-Screen limits:
If Cursor\x<=0:Cursor\dirX=Abs(Cursor\dirX):EndIf
If Cursor\x>=RX.w:Cursor\dirX=-Abs(Cursor\dirX):EndIf
If Cursor\y<=0:Cursor\dirY=Abs(Cursor\dirY):EndIf
If Cursor\y>=RY.w:Cursor\dirY=-Abs(Cursor\dirY):EndIf
Start3D()
ForEach Capsule()
; Ball-Screen limits:
If Capsule()\x<=0:Capsule()\dirX=Abs(Capsule()\dirX):EndIf
If Capsule()\x>=RX.w:Capsule()\dirX=-Abs(Capsule()\dirX):EndIf
If Capsule()\y<=0:Capsule()\dirY=Abs(Capsule()\dirY):EndIf
If Capsule()\y>=RY.w:Capsule()\dirY=-Abs(Capsule()\dirY):EndIf
; Ball-moving:
Capsule()\x+Capsule()\dirX:Capsule()\y+Capsule()\dirY;<-Coordenadas actuales de Ball (se suma a las anteriores el vector director)
; collision:
*i.balls=@Capsule()
While NextElement(Capsule())
If SpritePixelCollision(*i\sprite,*i\x-*i\HalfWidth,*i\y-*i\HalfHeight,Capsule()\sprite,Capsule()\x-Capsule()\HalfWidth,Capsule()\y-Capsule()\HalfHeight);Si hay colisión:
Shock(*i)
EndIf
Wend
ChangeCurrentElement(Capsule(),*i)
If SpritePixelCollision(Cursor\sprite,Cursor\x-Cursor\HalfWidth,Cursor\y-Cursor\HalfHeight,*i\sprite,*i\x-*i\HalfWidth,*i\y-*i\HalfHeight);Si hay colisión:
Shock(@Cursor)
EndIf
DisplaySprite3D(*i\sprite,*i\x-*i\HalfWidth,*i\y-*i\HalfHeight,255)
Next
DisplaySprite3D(Cursor\sprite,Cursor\x-Cursor\HalfWidth,Cursor\y-Cursor\HalfHeight,255)
Stop3D()
FlipBuffers()
Until KeyboardPushed(#PB_Key_All)
CloseScreen()
End
If you chack the CPU % use in the first time and compare to the second time, you will see it is the same 8O 8O 8O
Do you think that the first execution eats 100% CPU and 2nd 100% too? That is simply a deceit.
I am not sure if wilbert method is the best or the right one.
What I can and must say to Fred is that blueMSX, MAME32, and ZSNES are optimal in this ESSENTIAL matter, and all three are OPEN SOURCE.
I've wrote to blueMSX main author about this quest, but surely and logically he will answer me something like: sorry, i have no time to teach; blueMSX is OPENSOURCE software.
Sorry my insistence, Fred, but you must consider this matter as
crucial if you want that PB is good for 2D and 3D graphics performance.