But sometimes you need more control over brush transparency, and then drawing directly to alpha channel of the brush with different alpha intensity values is the best way to go.
For an example say you have a game, where you control a little rotating space ship and can shoot some baddies. To make it look a little more interesting, you want some gradually fading flames coming out from the back of space ship when thrusting.
Code: Select all
@APPICON {Ic16x16 = "my16x16icon.png",
Ic24x24 = "my24x24icon.png",
Ic32x32 = "my32x32icon.png",
Ic48x48 = "my48x48icon.png",
Ic128x128 = "my128x128icon.png",
Ic256x256 = "my256x256icon.png",
Ic512x512 = "my512x512icon.png"}
@SCREEN {Mode = "Windowed"}
@VERSION 2,0 /* Hollywood 2.0 strictly required */
/*
** External data
*/
@BRUSH 2, "ship.png", {LoadAlpha = True}
@BRUSH 4, "flame.png", {LoadAlpha = True}
@BRUSH 6, "shot.png", {LoadAlpha = True}
@BRUSH 7, "enemy.png", {LoadAlpha = True}
@ANIM 1, "explosion.png", {LoadAlpha = True, X = 0, Y = 0, Width = 64, Height = 64, Frames = 6, FPR = 1 }
@DISPLAY {Width = 800, Height = 600, Title = "SpaceMines"}
player = {}
player.x! = (800 - 64)/2
player.y! = (600 - 64)/2
player.angle = 0
player.speed! = 0
Function player:move(xs!, ys!)
self.x! = self.x! + xs!
self.y! = self.y! + ys!
Local ix = Int(self.x!)
Local fx = Frac(self.x!)
Local iy = Int(self.y!)
Local fy = Frac(self.y!)
self.x! = (ix + 800) % 800 + fx
self.y! = (iy + 600) % 600 + fy
EndFunction
Function player:draw()
Local w = GetAttribute(#BRUSH,3,#ATTRWIDTH)
Local h = GetAttribute(#BRUSH,3,#ATTRHEIGHT)
DisplayBrush(3, self.x! - w/2, self.y! - h/2)
EndFunction
Function player:rotate(angle)
CopyBrush(2,3)
RotateBrush(3, angle)
EndFunction
flames = { flames = {} }
Function flames:add(x, y, scale, alpha)
Local flame = { x = x, y = y, scale = scale, alpha = alpha }
InsertItem(self.flames, flame)
EndFunction
Function flames:del(pos)
RemoveItem(self.flames, pos)
EndFunction
Function flames:animate()
Local a, b = NextItem(self.flames)
While GetType(a) <> #NIL
b.alpha = b.alpha - 3.75
If b.alpha < 0
self:del(a)
EndIf
b.scale = b.scale + 0.05
If b.scale > 2
b.scale = 2
EndIf
a, b = NextItem(self.flames, a)
Wend
EndFunction
Function flames:draw()
Local a, b = NextItem(self.flames)
While GetType(a) <> #NIL
CopyBrush(4, 5)
SelectAlphaChannel(5)
SetAlphaIntensity(0)
Cls
SetAlphaIntensity(b.alpha)
DisplayBrush(4, #CENTER, #CENTER)
EndSelect
ScaleBrush(5, 64 * b.scale, 64 * b.scale)
DisplayBrush(5, #CENTER - 400 + b.x, #CENTER - 300 + b.y)
a, b = NextItem(self.flames, a)
Wend
EndFunction
explosions = { explosions = {} }
Function explosions:add(x, y)
Local explosion = { x = x, y = y, frame = 1 }
InsertItem(self.explosions, explosion)
EndFunction
Function explosions:del(pos)
RemoveItem(self.explosions, pos)
EndFunction
Function explosions:animate()
Local time = GetTimer(2)
If time > 50
Local a, b = NextItem(self.explosions)
While GetType(a) <> #NIL
b.frame = b.frame + 1
If b.frame >= 7
self:del(a)
EndIf
a, b = NextItem(self.explosions, a)
Wend
ResetTimer(2)
EndIf
EndFunction
Function explosions:draw()
Local framesy = { 63, 127, 191, 255, 319, 383, 447 }
Local a, b = NextItem(self.explosions)
While GetType(a) <> #NIL
DisplayAnimFrame(1, #CENTER - 400 + b.x, #CENTER - 300 + b.y, b.frame)
a, b = NextItem(self.explosions, a)
Wend
EndFunction
shots = { shots = {}}
Function shots:add(x, y, xs, ys)
Local shot = { x = x, y = y, xs = xs, ys = ys }
InsertItem(self.shots, shot)
EndFunction
Function shots:del(pos)
RemoveItem(self.shots, pos)
EndFunction
Function shots:move()
Local a, b = NextItem(self.shots)
While GetType(a) <> #NIL
b.x = b.x + b.xs
b.y = b.y + b.ys
If b.x < 0
self:del(a)
ElseIf b.x > 800
self:del(a)
EndIf
If b.y < 0
self:del(a)
ElseIf b.y > 600
self:del(a)
EndIf
a, b = NextItem(self.shots, a)
Wend
EndFunction
Function shots:draw()
Local a, b = NextItem(self.shots)
While GetType(a) <> #NIL
DisplayBrush(6, #CENTER - 400 + b.x, #CENTER - 300 + b.y )
a, b = NextItem(self.shots, a)
Wend
EndFunction
Function shots:collision()
Local w1 = GetAttribute(#BRUSH,6,#ATTRWIDTH)
Local h1 = GetAttribute(#BRUSH,6,#ATTRHEIGHT)
Local w2 = GetAttribute(#BRUSH,7,#ATTRWIDTH)
Local h2 = GetAttribute(#BRUSH,7,#ATTRHEIGHT)
Local k, c
Local a, b = NextItem(self.shots)
While GetType(a) <> #NIL
c = ListItems(baddies.baddies)
For k = 0 To c-1
If Collision(#BRUSH, 6, b.x - w1/2, b.y - h1/2, 7, baddies.baddies[k].x - w2/2, baddies.baddies[k].y - h2/2)
explosions:add(b.x, b.y)
shots:del(a)
baddies:del(k)
points = points + 1
Break
EndIf
Next
a, b = NextItem(self.shots, a)
Wend
EndFunction
starfield = { SP = {}, XS = {}, YS = {}, CL = {} }
Function starfield:init()
Local k
For k = 0 To 9
self.XS[k] = Rnd(800)
self.YS[k] = Rnd(600)
self.SP[k] = 0.5
self.CL[k] = $888888
Next
For k = 10 To 20
self.XS[k] = Rnd(800)
self.YS[k] = Rnd(600)
self.SP[k] = 1
self.CL[k] = $888888
Next
For k = 21 To 30
self.XS[k] = Rnd(800)
self.YS[k] = Rnd(600)
self.SP[k] = 1.5
self.CL[k] = $888888
Next
For k = 31 To 40
self.XS[k] = Rnd(800)
self.YS[k] = Rnd(600)
self.SP[k] = 2
self.CL[k] = $DDDDDD
Next
For k = 41 To 50
self.XS[k] = Rnd(800)
self.YS[k] = Rnd(600)
self.SP[k] = 2.5
self.CL[k] = $DDDDDD
Next
For k = 51 To 60
self.XS[k] = Rnd(800)
self.YS[k] = Rnd(600)
self.SP[k] = 3
self.CL[k] = $DDDDDD
Next
EndFunction
Function starfield:draw()
For Local k = 0 To 60
Plot(self.XS[k], self.YS[k], self.CL[k])
self.XS[k] = self.XS[k] + self.SP[k]
If self.XS[k] > 800 Then self.XS[k] = 0
Next
EndFunction
baddies = { baddies = {} }
Function baddies:init()
For Local k = 0 To 4
Local badguy = {}
badguy.x = Rnd(800)
badguy.y = 0
badguy.xs = (Rnd(6) + 1) / 4
badguy.ys = (Rnd(6) + 1) / 4
InsertItem(self.baddies, badguy)
Next
For k = 0 To 4
badguy = {}
badguy.x = Rnd(800)
badguy.y = 600
badguy.xs = -(Rnd(6) + 1) / 4
badguy.ys = -(Rnd(6) + 1) / 4
InsertItem(self.baddies, badguy)
Next
EndFunction
Function baddies:del(pos)
RemoveItem(self.baddies, pos)
EndFunction
Function baddies:move()
Local ix, fx, iy, fy
Local a, b = NextItem(self.baddies)
While GetType(a) <> #NIL
b.x = b.x + b.xs
b.y = b.y + b.ys
ix = Int(b.x)
fx = Frac(b.x)
iy = Int(b.y)
fy = Frac(b.y)
b.x = (ix + 800) % 800 + fx
b.y = (iy + 600) % 600 + fy
a, b = NextItem(self.baddies, a)
Wend
EndFunction
Function baddies:draw()
Local a, b = NextItem(self.baddies)
While GetType(a) <> #NIL
DisplayBrush(7, #CENTER - 400 + b.x, #CENTER - 300 + b.y )
a, b = NextItem(self.baddies, a)
Wend
EndFunction
Function baddies:collision()
Local w1 = GetAttribute(#BRUSH,7,#ATTRWIDTH)
Local h1 = GetAttribute(#BRUSH,7,#ATTRHEIGHT)
Local w2 = GetAttribute(#BRUSH,3,#ATTRWIDTH)
Local h2 = GetAttribute(#BRUSH,3,#ATTRHEIGHT)
Local k, c
Local a, b = NextItem(self.baddies)
While GetType(a) <> #NIL
If Collision(#BRUSH, 7, b.x - w1/2, b.y - h1/2, 3, player.x! - w2/2, player.y! - h2/2)
explosions:add(b.x, b.y)
baddies:del(a)
Break
EndIf
a, b = NextItem(self.baddies, a)
Wend
EndFunction
Function p_MainLoop()
If IsKeyDown("LEFT")
player.angle = (player.angle + 360) % 360 + 4
ElseIf IsKeyDown("RIGHT")
player.angle = (player.angle + 360) % 360 - 4
EndIf
Local xd! = costable[player.angle + 90]
Local yd! = sintable[player.angle - 90]
Local xs! = xd! * player.speed!
Local ys! = yd! * player.speed!
If IsKeyDown("UP")
player.speed! = player.speed! + 0.35
If player.speed! > 4
player.speed! = 4
EndIf
If Rnd(100) > (100 - player.speed! * 2.5)
flames:add(player.x! - 40 *xd!, player.y! - 40 * yd!, 0.5, 128)
EndIf
Else
player.speed! = player.speed! - 0.25
If player.speed! < 0
player.speed! = 0
EndIf
EndIf
If IsKeyDown("LCONTROL")
Local time = GetTimer(1)
If time > 500
shots:add(player.x! + 32 * xd!, player.y! + 32 * yd!, 20 *xd!, 20 * yd!)
ResetTimer(1)
EndIf
EndIf
DisplayBrush(1, #CENTER, #CENTER)
player:move(xs!, ys!)
player:rotate(player.angle)
baddies:move()
shots:move()
shots:collision()
baddies:collision()
flames:animate()
starfield:draw()
player:draw()
baddies:draw()
flames:draw()
explosions:draw()
explosions:animate()
shots:draw()
TextOut(#LEFT, #TOP, AddStr(pointinfo$, points))
Flip
EndFunction
sintable = {}
For i = -450 To 450 Do sintable[i] = Sin(Rad(i))
costable = {}
For i = -450 To 450 Do costable[i] = Cos(Rad(i))
points = 0
pointinfo$ = "SCORE: "
starfield:init()
baddies:init()
CreateBrush(1, 800, 600, #BLACK)
ScaleBrush(7, 45, 45, True)
EscapeQuit(True)
BeginDoubleBuffer
StartTimer(1)
StartTimer(2)
SetInterval(1, p_MainLoop, 1000/50) ; 50fps
Repeat
WaitEvent
Forever