作者:薛萌
演示效果
代码
# 在 JavaScript 编程界面中,将此代码复制进去即可。
class Vec2 {
x : number
y : number
constructor(x : number, y : number) {
this.x = x
this.y = y
}
Length() : number {
return Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2))
}
Normalize() {
let s = this.Length()
if(s != 0) {
this.x = this.x / s
this.y = this.y / s
}
}
GetNormalize() : Vec2 {
let v = new Vec2(this.x, this.y)
v.Normalize()
return v
}
Add(rhs : Vec2) : Vec2 {
let x = this.x + rhs.x
let y = this.y + rhs.y
return new Vec2(x, y)
}
Mul(n : number) : Vec2 {
let x = this.x * n
let y = this.y * n
return new Vec2(x, y)
}
}
function ToLeft(a : Vec2, b : Vec2, p : Vec2 )
{
// | a.x a.y 1 |
// | b.x b.y 1 |
// | p.x p.y 1 |
return a.x * b.y + b.x * p.y + p.x * a.y - a.y * b.x - b.y * p.x - p.y * a.x > 0.0;
}
let w = scene.screenWidth()
let h = scene.screenHeight()
let block_size = 10
let row = 4
let col = 16
enum ItemType {
None = 0,
Green = 2,
Yellow = 3,
Red = 4,
Purple = 5
}
enum BlockType {
None = 0,
Red = 1,
Green = 2,
Yellow = 3,
Purple = 4,
Brown = 5
}
enum CollisionEdge {
None = 0,
Top = 1,
Bottom = 2,
Left = 3,
Right = 4
}
let Blocks : number[][] = [
[3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3],
[4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4],
[5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5],
[1, 2, 3, 4, 5, 4, 3, 2, 2, 3, 4, 5, 4, 3, 2, 1],
[1, 2, 3, 4, 5, 4, 3, 1, 1, 3, 4, 5, 4, 3, 2, 1],
]
class Platform {
platform : Sprite
x : number
y : number
constructor(x : number, y : number) {
this.x = x
this.y = y
this.platform = sprites.create(assets.image`platform`, SpriteKind.Player)
this.platform.setPosition(this.x, this.y)
this.platform.setStayInScreen(true)
controller.moveSprite(this.platform, 80, 0)
}
}
class Ball {
ball : Sprite
speed : number
constructor(x : number, y : number, dir : Vec2) {
this.speed = 20
this.ball = sprites.create(assets.image`ball`, SpriteKind.Projectile)
this.ball.setPosition(x, y)
this.ball.setStayInScreen(true)
this.ball.setBounceOnWall(true)
dir.Normalize()
this.SetVelocity(dir)
}
GetDir() : Vec2 {
let dir = new Vec2(this.ball.vx, this.ball.vy)
dir.Normalize()
return dir
}
SpeedUp(p : number) {
this.speed += this.speed * p
this.SetVelocity(this.GetDir())
}
SetVelocity(dir : Vec2) {
this.ball.setVelocity(dir.x * this.speed, dir.y * this.speed)
}
GetPos() : Vec2 {
return new Vec2(this.ball.x, this.ball.y)
}
}
class MyBlock {
x : number
y : number
block : Sprite
px : number
py : number
HP : number
constructor(x : number, y : number, blockType : number) {
this.HP = blockType
this.x = x
this.y = y
this.CreateBlockByType(blockType)
this.px = this.x * block_size + block_size * 0.5
this.py = this.y * block_size + block_size * 0.5
}
CreateBlockByType(blockType : number) {
if(blockType == 1) {
this.block = sprites.create(assets.image`red_block`, SpriteKind.Enemy)
} else if(blockType == 2) {
this.block = sprites.create(assets.image`green_block`, SpriteKind.Enemy)
} else if(blockType == 3) {
this.block = sprites.create(assets.image`yellow_block`, SpriteKind.Enemy)
} else if(blockType == 4) {
this.block = sprites.create(assets.image`purple_block`, SpriteKind.Enemy)
} else if(blockType == 5) {
this.block = sprites.create(assets.image`brown_block`, SpriteKind.Enemy)
}
}
BeBreakOut() : boolean {
--this.HP
if(this.HP == 0) {
music.bigCrash.play()
return true
}
music.smallCrash.play()
this.block.destroy()
this.CreateBlockByType(this.HP)
this.Render()
return false
}
GetVertics() : Vec2[] {
let p1 = new Vec2(this.px - block_size * 0.5, this.py - block_size * 0.5)
let p2 = new Vec2(this.px - block_size * 0.5, this.py + block_size * 0.5)
let p3 = new Vec2(this.px + block_size * 0.5, this.py + block_size * 0.5)
let p4 = new Vec2(this.px + block_size * 0.5, this.py - block_size * 0.5)
return [p1, p2, p3, p4]
}
Render(){
this.block.setPosition(this.px, this.py)
}
}
class Item {
item : Sprite
x : number
y : number
speed : number
itemType : ItemType
constructor(x : number, y : number, itemType : ItemType) {
this.x = x
this.y = y
this.speed = 10
this.itemType = itemType
switch(itemType) {
case ItemType.Green:
this.item = sprites.create(assets.image`two`, SpriteKind.Food)
break
case ItemType.Yellow:
this.item = sprites.create(assets.image`three`, SpriteKind.Food)
break
case ItemType.Red:
this.item = sprites.create(assets.image`four`, SpriteKind.Food)
break
case ItemType.Purple:
this.item = sprites.create(assets.image`five`, SpriteKind.Food)
break
}
this.item.setPosition(x, y)
this.item.setVelocity(0, this.speed)
}
}
let liveItems : Item[] = []
sprites.onOverlap(SpriteKind.Food, SpriteKind.Player, function (foodSprite, playerSprite) {
music.beamUp.play()
for(let i = 0; i < liveItems.length; ++i) {
let curItem = liveItems[i]
if(curItem.item == foodSprite) {
let deadItem = liveItems.removeAt(i)
deadItem.item.destroy()
if(ballList.length < 25) {
GenNewBall(deadItem.itemType)
} else {
for(let ii = 0; ii < ballList.length; ++ii) {
let curBall = ballList[ii]
curBall.SpeedUp(0.2)
}
}
break
}
}
})
let D2R = Math.PI / 180
function RotateVector(v : Vec2, angle : number, isClockwise : boolean) : Vec2 {
let vv : Vec2
if(isClockwise == true) {
vv = new Vec2(-v.y, v.x)
} else {
vv = new Vec2(v.y, -v.x)
}
let xl : number
let yl : number
xl = Math.cos(angle * D2R)
yl = Math.sin(angle * D2R)
let xx = v.Mul(xl)
let yy = vv.Mul(yl)
let newV : Vec2 = xx.Add(yy)
return newV
}
function GenNewBall(count : number) {
if(ballList.length > 100) {
return
}
let newBalls : Ball[] = []
if(count == 2) {
for(let i = 0; i < ballList.length; ++i) {
let curBall = ballList[i]
let v1 = RotateVector(curBall.GetDir(), 15, true)
let v2 = RotateVector(curBall.GetDir(), 15, false)
curBall.SetVelocity(v1)
let pos = curBall.GetPos()
let ball = new Ball(pos.x, pos.y, v2)
newBalls.push(ball)
}
} else if(count == 3) {
for(let i = 0; i < ballList.length; ++i) {
let curBall = ballList[i]
let v1 = RotateVector(curBall.GetDir(), 120, true)
let v2 = RotateVector(curBall.GetDir(), 120, false)
let pos = curBall.GetPos()
let ball1 = new Ball(pos.x, pos.y, v1)
let ball2 = new Ball(pos.x, pos.y, v2)
newBalls.push(ball1)
newBalls.push(ball2)
}
} else if(count == 4) {
for(let i = 0; i < ballList.length; ++i) {
let curBall = ballList[i]
let v1 = RotateVector(curBall.GetDir(), 15, true)
let v2 = RotateVector(curBall.GetDir(), 45, true)
let v3 = RotateVector(curBall.GetDir(), 15, false)
let v4 = RotateVector(curBall.GetDir(), 45, false)
curBall.SetVelocity(v1)
let pos = curBall.GetPos()
let ball2 = new Ball(pos.x, pos.y, v2)
let ball3 = new Ball(pos.x, pos.y, v3)
let ball4 = new Ball(pos.x, pos.y, v4)
newBalls.push(ball2)
newBalls.push(ball3)
newBalls.push(ball4)
}
} else if(count == 5) {
for(let i = 0; i < ballList.length; ++i) {
let curBall = ballList[i]
let v1 = RotateVector(curBall.GetDir(), 72, true)
let v2 = RotateVector(curBall.GetDir(), 144, true)
let v3 = RotateVector(curBall.GetDir(), 72, false)
let v4 = RotateVector(curBall.GetDir(), 144, false)
let pos = curBall.GetPos()
let ball1 = new Ball(pos.x, pos.y, v1)
let ball2 = new Ball(pos.x, pos.y, v2)
let ball3 = new Ball(pos.x, pos.y, v3)
let ball4 = new Ball(pos.x, pos.y, v4)
newBalls.push(ball1)
newBalls.push(ball2)
newBalls.push(ball3)
newBalls.push(ball4)
}
}
for(let i = 0; i < newBalls.length; ++i) {
ballList.push(newBalls[i])
}
}
function IsIntersection(p1 : Vec2, p2 : Vec2, p3 : Vec2, p4 : Vec2) : boolean {
if(ToLeft(p1, p2, p3) && ToLeft(p1, p2, p4)) {
return false
}
if(!ToLeft(p1, p2, p3) && !ToLeft(p1, p2, p4)) {
return false
}
if(ToLeft(p3, p4, p1) && ToLeft(p3, p4, p2)) {
return false
}
if(!ToLeft(p3, p4, p1) && !ToLeft(p3, p4, p2)) {
return false
}
return true
}
let BlocksObjects : MyBlock[] = []
for(let i = 0; i < row; ++i) {
for(let j = 0; j < col; ++j) {
if(Blocks[i][j] > 0) {
BlocksObjects.push(new MyBlock(j, i, Blocks[i][j]))
}
}
}
let platform = new Platform(w / 2, h - 20)
let ballList : Ball[] = []
ballList.push(new Ball(w / 2, h / 2, new Vec2(1, 1)))
for(let i = 0; i < BlocksObjects.length; ++i)
{
BlocksObjects[i].Render()
}
function GetCollisionEdge(sprite : Sprite, otherSprite : Sprite) : CollisionEdge {
let otherTop = otherSprite.top
let otherBottom = otherSprite.bottom
let otherLeft = otherSprite.left
let otherRight = otherSprite.right
let otherCenter = new Vec2(otherLeft / 2 + otherRight / 2, otherTop / 2 + otherBottom / 2)
let otherLeftTop = new Vec2(otherLeft, otherTop)
let otherLeftBottom = new Vec2(otherLeft, otherBottom)
let otherRightTop = new Vec2(otherRight, otherTop)
let otherRightBottom = new Vec2(otherRight, otherBottom)
let top = sprite.top
let bottom = sprite.bottom
let left = sprite.left
let right = sprite.right
let center = new Vec2(left / 2 + right / 2, top / 2 + bottom / 2)
let leftTop = new Vec2(left, top)
let leftBottom = new Vec2(left, bottom)
let rightTop = new Vec2(right, top)
let rightBottom = new Vec2(right, bottom)
if(IsIntersection(center, otherCenter, otherLeftTop, otherLeftBottom)) {
return CollisionEdge.Left
} else if(IsIntersection(center, otherCenter, otherRightTop, otherRightBottom)) {
return CollisionEdge.Right
} else if(IsIntersection(center, otherCenter, otherLeftTop, otherRightTop)) {
return CollisionEdge.Top
}else if(IsIntersection(center, otherCenter, otherLeftBottom, otherRightBottom)) {
return CollisionEdge.Bottom
}
return CollisionEdge.None
}
sprites.onOverlap(SpriteKind.Projectile, SpriteKind.Player, function (sprite, otherSprite) {
let edge = GetCollisionEdge(sprite, otherSprite)
music.pewPew.play()
switch(edge)
{
case CollisionEdge.Top:
if(sprite.vy > 0){
sprite.vy = -sprite.vy
if(sprite.x < otherSprite.x) {
sprite.vx -= randint(0, 10) / 10.0
} else if(sprite.x > otherSprite.x) {
sprite.vx += randint(0, 10) / 10.0
}
}
break
case CollisionEdge.Bottom:
if(sprite.vy < 0){
sprite.vy = -sprite.vy
}
break
case CollisionEdge.Left:
if(sprite.vx > 0) {
sprite.vx = -sprite.vx
}
break
case CollisionEdge.Right:
if(sprite.vx < 0){
sprite.vx = -sprite.vx
}
break
}
})
sprites.onOverlap(SpriteKind.Projectile, SpriteKind.Enemy, function (sprite, otherSprite) {
let edge = GetCollisionEdge(sprite, otherSprite)
let r = randint(1, 100)
if(r > 80 && ballList.length < 25 && liveItems.length < 3) {
let item = new Item(sprite.x, sprite.y, randint(2, 5))
liveItems.push(item)
}
switch(edge)
{
case CollisionEdge.Top:
if(sprite.vy > 0){
sprite.vy = -sprite.vy * 1.05
}
break
case CollisionEdge.Bottom:
if(sprite.vy < 0){
sprite.vy = -sprite.vy * 1.05
}
break
case CollisionEdge.Left:
if(sprite.vx > 0) {
sprite.vx = -sprite.vx * 1.05
}
break
case CollisionEdge.Right:
if(sprite.vx < 0){
sprite.vx = -sprite.vx * 1.05
}
break
}
for(let i = 0; i < BlocksObjects.length; ++i) {
let myBlock = BlocksObjects[i]
if(myBlock.block == otherSprite) {
if(myBlock.BeBreakOut() == true) {
let item = BlocksObjects.removeAt(i)
item.block.destroy()
if(BlocksObjects.length == 0) {
music.powerUp.play()
}
}
break
}
}
})
game.onUpdate(function() {
let background = scene.backgroundImage();
background.fill(0)
for(let i = ballList.length - 1; i >= 0; --i)
{
let pos = ballList[i].GetPos()
if(pos.y > 117) {
let ball = ballList.removeAt(i)
ball.ball.destroy()
}
}
})