作者:薛萌

演示效果

happyZ.gif

代码

  1. # JavaScript 编程界面中,将此代码复制进去即可。
  2. class Vec2 {
  3. x : number
  4. y : number
  5. constructor(x : number, y : number) {
  6. this.x = x
  7. this.y = y
  8. }
  9. Length() : number {
  10. return Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2))
  11. }
  12. Normalize() {
  13. let s = this.Length()
  14. if(s != 0) {
  15. this.x = this.x / s
  16. this.y = this.y / s
  17. }
  18. }
  19. GetNormalize() : Vec2 {
  20. let v = new Vec2(this.x, this.y)
  21. v.Normalize()
  22. return v
  23. }
  24. Add(rhs : Vec2) : Vec2 {
  25. let x = this.x + rhs.x
  26. let y = this.y + rhs.y
  27. return new Vec2(x, y)
  28. }
  29. Mul(n : number) : Vec2 {
  30. let x = this.x * n
  31. let y = this.y * n
  32. return new Vec2(x, y)
  33. }
  34. }
  35. function ToLeft(a : Vec2, b : Vec2, p : Vec2 )
  36. {
  37. // | a.x a.y 1 |
  38. // | b.x b.y 1 |
  39. // | p.x p.y 1 |
  40. 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;
  41. }
  42. let w = scene.screenWidth()
  43. let h = scene.screenHeight()
  44. let block_size = 10
  45. let row = 4
  46. let col = 16
  47. enum ItemType {
  48. None = 0,
  49. Green = 2,
  50. Yellow = 3,
  51. Red = 4,
  52. Purple = 5
  53. }
  54. enum BlockType {
  55. None = 0,
  56. Red = 1,
  57. Green = 2,
  58. Yellow = 3,
  59. Purple = 4,
  60. Brown = 5
  61. }
  62. enum CollisionEdge {
  63. None = 0,
  64. Top = 1,
  65. Bottom = 2,
  66. Left = 3,
  67. Right = 4
  68. }
  69. let Blocks : number[][] = [
  70. [3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3],
  71. [4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4],
  72. [5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5],
  73. [1, 2, 3, 4, 5, 4, 3, 2, 2, 3, 4, 5, 4, 3, 2, 1],
  74. [1, 2, 3, 4, 5, 4, 3, 1, 1, 3, 4, 5, 4, 3, 2, 1],
  75. ]
  76. class Platform {
  77. platform : Sprite
  78. x : number
  79. y : number
  80. constructor(x : number, y : number) {
  81. this.x = x
  82. this.y = y
  83. this.platform = sprites.create(assets.image`platform`, SpriteKind.Player)
  84. this.platform.setPosition(this.x, this.y)
  85. this.platform.setStayInScreen(true)
  86. controller.moveSprite(this.platform, 80, 0)
  87. }
  88. }
  89. class Ball {
  90. ball : Sprite
  91. speed : number
  92. constructor(x : number, y : number, dir : Vec2) {
  93. this.speed = 20
  94. this.ball = sprites.create(assets.image`ball`, SpriteKind.Projectile)
  95. this.ball.setPosition(x, y)
  96. this.ball.setStayInScreen(true)
  97. this.ball.setBounceOnWall(true)
  98. dir.Normalize()
  99. this.SetVelocity(dir)
  100. }
  101. GetDir() : Vec2 {
  102. let dir = new Vec2(this.ball.vx, this.ball.vy)
  103. dir.Normalize()
  104. return dir
  105. }
  106. SpeedUp(p : number) {
  107. this.speed += this.speed * p
  108. this.SetVelocity(this.GetDir())
  109. }
  110. SetVelocity(dir : Vec2) {
  111. this.ball.setVelocity(dir.x * this.speed, dir.y * this.speed)
  112. }
  113. GetPos() : Vec2 {
  114. return new Vec2(this.ball.x, this.ball.y)
  115. }
  116. }
  117. class MyBlock {
  118. x : number
  119. y : number
  120. block : Sprite
  121. px : number
  122. py : number
  123. HP : number
  124. constructor(x : number, y : number, blockType : number) {
  125. this.HP = blockType
  126. this.x = x
  127. this.y = y
  128. this.CreateBlockByType(blockType)
  129. this.px = this.x * block_size + block_size * 0.5
  130. this.py = this.y * block_size + block_size * 0.5
  131. }
  132. CreateBlockByType(blockType : number) {
  133. if(blockType == 1) {
  134. this.block = sprites.create(assets.image`red_block`, SpriteKind.Enemy)
  135. } else if(blockType == 2) {
  136. this.block = sprites.create(assets.image`green_block`, SpriteKind.Enemy)
  137. } else if(blockType == 3) {
  138. this.block = sprites.create(assets.image`yellow_block`, SpriteKind.Enemy)
  139. } else if(blockType == 4) {
  140. this.block = sprites.create(assets.image`purple_block`, SpriteKind.Enemy)
  141. } else if(blockType == 5) {
  142. this.block = sprites.create(assets.image`brown_block`, SpriteKind.Enemy)
  143. }
  144. }
  145. BeBreakOut() : boolean {
  146. --this.HP
  147. if(this.HP == 0) {
  148. music.bigCrash.play()
  149. return true
  150. }
  151. music.smallCrash.play()
  152. this.block.destroy()
  153. this.CreateBlockByType(this.HP)
  154. this.Render()
  155. return false
  156. }
  157. GetVertics() : Vec2[] {
  158. let p1 = new Vec2(this.px - block_size * 0.5, this.py - block_size * 0.5)
  159. let p2 = new Vec2(this.px - block_size * 0.5, this.py + block_size * 0.5)
  160. let p3 = new Vec2(this.px + block_size * 0.5, this.py + block_size * 0.5)
  161. let p4 = new Vec2(this.px + block_size * 0.5, this.py - block_size * 0.5)
  162. return [p1, p2, p3, p4]
  163. }
  164. Render(){
  165. this.block.setPosition(this.px, this.py)
  166. }
  167. }
  168. class Item {
  169. item : Sprite
  170. x : number
  171. y : number
  172. speed : number
  173. itemType : ItemType
  174. constructor(x : number, y : number, itemType : ItemType) {
  175. this.x = x
  176. this.y = y
  177. this.speed = 10
  178. this.itemType = itemType
  179. switch(itemType) {
  180. case ItemType.Green:
  181. this.item = sprites.create(assets.image`two`, SpriteKind.Food)
  182. break
  183. case ItemType.Yellow:
  184. this.item = sprites.create(assets.image`three`, SpriteKind.Food)
  185. break
  186. case ItemType.Red:
  187. this.item = sprites.create(assets.image`four`, SpriteKind.Food)
  188. break
  189. case ItemType.Purple:
  190. this.item = sprites.create(assets.image`five`, SpriteKind.Food)
  191. break
  192. }
  193. this.item.setPosition(x, y)
  194. this.item.setVelocity(0, this.speed)
  195. }
  196. }
  197. let liveItems : Item[] = []
  198. sprites.onOverlap(SpriteKind.Food, SpriteKind.Player, function (foodSprite, playerSprite) {
  199. music.beamUp.play()
  200. for(let i = 0; i < liveItems.length; ++i) {
  201. let curItem = liveItems[i]
  202. if(curItem.item == foodSprite) {
  203. let deadItem = liveItems.removeAt(i)
  204. deadItem.item.destroy()
  205. if(ballList.length < 25) {
  206. GenNewBall(deadItem.itemType)
  207. } else {
  208. for(let ii = 0; ii < ballList.length; ++ii) {
  209. let curBall = ballList[ii]
  210. curBall.SpeedUp(0.2)
  211. }
  212. }
  213. break
  214. }
  215. }
  216. })
  217. let D2R = Math.PI / 180
  218. function RotateVector(v : Vec2, angle : number, isClockwise : boolean) : Vec2 {
  219. let vv : Vec2
  220. if(isClockwise == true) {
  221. vv = new Vec2(-v.y, v.x)
  222. } else {
  223. vv = new Vec2(v.y, -v.x)
  224. }
  225. let xl : number
  226. let yl : number
  227. xl = Math.cos(angle * D2R)
  228. yl = Math.sin(angle * D2R)
  229. let xx = v.Mul(xl)
  230. let yy = vv.Mul(yl)
  231. let newV : Vec2 = xx.Add(yy)
  232. return newV
  233. }
  234. function GenNewBall(count : number) {
  235. if(ballList.length > 100) {
  236. return
  237. }
  238. let newBalls : Ball[] = []
  239. if(count == 2) {
  240. for(let i = 0; i < ballList.length; ++i) {
  241. let curBall = ballList[i]
  242. let v1 = RotateVector(curBall.GetDir(), 15, true)
  243. let v2 = RotateVector(curBall.GetDir(), 15, false)
  244. curBall.SetVelocity(v1)
  245. let pos = curBall.GetPos()
  246. let ball = new Ball(pos.x, pos.y, v2)
  247. newBalls.push(ball)
  248. }
  249. } else if(count == 3) {
  250. for(let i = 0; i < ballList.length; ++i) {
  251. let curBall = ballList[i]
  252. let v1 = RotateVector(curBall.GetDir(), 120, true)
  253. let v2 = RotateVector(curBall.GetDir(), 120, false)
  254. let pos = curBall.GetPos()
  255. let ball1 = new Ball(pos.x, pos.y, v1)
  256. let ball2 = new Ball(pos.x, pos.y, v2)
  257. newBalls.push(ball1)
  258. newBalls.push(ball2)
  259. }
  260. } else if(count == 4) {
  261. for(let i = 0; i < ballList.length; ++i) {
  262. let curBall = ballList[i]
  263. let v1 = RotateVector(curBall.GetDir(), 15, true)
  264. let v2 = RotateVector(curBall.GetDir(), 45, true)
  265. let v3 = RotateVector(curBall.GetDir(), 15, false)
  266. let v4 = RotateVector(curBall.GetDir(), 45, false)
  267. curBall.SetVelocity(v1)
  268. let pos = curBall.GetPos()
  269. let ball2 = new Ball(pos.x, pos.y, v2)
  270. let ball3 = new Ball(pos.x, pos.y, v3)
  271. let ball4 = new Ball(pos.x, pos.y, v4)
  272. newBalls.push(ball2)
  273. newBalls.push(ball3)
  274. newBalls.push(ball4)
  275. }
  276. } else if(count == 5) {
  277. for(let i = 0; i < ballList.length; ++i) {
  278. let curBall = ballList[i]
  279. let v1 = RotateVector(curBall.GetDir(), 72, true)
  280. let v2 = RotateVector(curBall.GetDir(), 144, true)
  281. let v3 = RotateVector(curBall.GetDir(), 72, false)
  282. let v4 = RotateVector(curBall.GetDir(), 144, false)
  283. let pos = curBall.GetPos()
  284. let ball1 = new Ball(pos.x, pos.y, v1)
  285. let ball2 = new Ball(pos.x, pos.y, v2)
  286. let ball3 = new Ball(pos.x, pos.y, v3)
  287. let ball4 = new Ball(pos.x, pos.y, v4)
  288. newBalls.push(ball1)
  289. newBalls.push(ball2)
  290. newBalls.push(ball3)
  291. newBalls.push(ball4)
  292. }
  293. }
  294. for(let i = 0; i < newBalls.length; ++i) {
  295. ballList.push(newBalls[i])
  296. }
  297. }
  298. function IsIntersection(p1 : Vec2, p2 : Vec2, p3 : Vec2, p4 : Vec2) : boolean {
  299. if(ToLeft(p1, p2, p3) && ToLeft(p1, p2, p4)) {
  300. return false
  301. }
  302. if(!ToLeft(p1, p2, p3) && !ToLeft(p1, p2, p4)) {
  303. return false
  304. }
  305. if(ToLeft(p3, p4, p1) && ToLeft(p3, p4, p2)) {
  306. return false
  307. }
  308. if(!ToLeft(p3, p4, p1) && !ToLeft(p3, p4, p2)) {
  309. return false
  310. }
  311. return true
  312. }
  313. let BlocksObjects : MyBlock[] = []
  314. for(let i = 0; i < row; ++i) {
  315. for(let j = 0; j < col; ++j) {
  316. if(Blocks[i][j] > 0) {
  317. BlocksObjects.push(new MyBlock(j, i, Blocks[i][j]))
  318. }
  319. }
  320. }
  321. let platform = new Platform(w / 2, h - 20)
  322. let ballList : Ball[] = []
  323. ballList.push(new Ball(w / 2, h / 2, new Vec2(1, 1)))
  324. for(let i = 0; i < BlocksObjects.length; ++i)
  325. {
  326. BlocksObjects[i].Render()
  327. }
  328. function GetCollisionEdge(sprite : Sprite, otherSprite : Sprite) : CollisionEdge {
  329. let otherTop = otherSprite.top
  330. let otherBottom = otherSprite.bottom
  331. let otherLeft = otherSprite.left
  332. let otherRight = otherSprite.right
  333. let otherCenter = new Vec2(otherLeft / 2 + otherRight / 2, otherTop / 2 + otherBottom / 2)
  334. let otherLeftTop = new Vec2(otherLeft, otherTop)
  335. let otherLeftBottom = new Vec2(otherLeft, otherBottom)
  336. let otherRightTop = new Vec2(otherRight, otherTop)
  337. let otherRightBottom = new Vec2(otherRight, otherBottom)
  338. let top = sprite.top
  339. let bottom = sprite.bottom
  340. let left = sprite.left
  341. let right = sprite.right
  342. let center = new Vec2(left / 2 + right / 2, top / 2 + bottom / 2)
  343. let leftTop = new Vec2(left, top)
  344. let leftBottom = new Vec2(left, bottom)
  345. let rightTop = new Vec2(right, top)
  346. let rightBottom = new Vec2(right, bottom)
  347. if(IsIntersection(center, otherCenter, otherLeftTop, otherLeftBottom)) {
  348. return CollisionEdge.Left
  349. } else if(IsIntersection(center, otherCenter, otherRightTop, otherRightBottom)) {
  350. return CollisionEdge.Right
  351. } else if(IsIntersection(center, otherCenter, otherLeftTop, otherRightTop)) {
  352. return CollisionEdge.Top
  353. }else if(IsIntersection(center, otherCenter, otherLeftBottom, otherRightBottom)) {
  354. return CollisionEdge.Bottom
  355. }
  356. return CollisionEdge.None
  357. }
  358. sprites.onOverlap(SpriteKind.Projectile, SpriteKind.Player, function (sprite, otherSprite) {
  359. let edge = GetCollisionEdge(sprite, otherSprite)
  360. music.pewPew.play()
  361. switch(edge)
  362. {
  363. case CollisionEdge.Top:
  364. if(sprite.vy > 0){
  365. sprite.vy = -sprite.vy
  366. if(sprite.x < otherSprite.x) {
  367. sprite.vx -= randint(0, 10) / 10.0
  368. } else if(sprite.x > otherSprite.x) {
  369. sprite.vx += randint(0, 10) / 10.0
  370. }
  371. }
  372. break
  373. case CollisionEdge.Bottom:
  374. if(sprite.vy < 0){
  375. sprite.vy = -sprite.vy
  376. }
  377. break
  378. case CollisionEdge.Left:
  379. if(sprite.vx > 0) {
  380. sprite.vx = -sprite.vx
  381. }
  382. break
  383. case CollisionEdge.Right:
  384. if(sprite.vx < 0){
  385. sprite.vx = -sprite.vx
  386. }
  387. break
  388. }
  389. })
  390. sprites.onOverlap(SpriteKind.Projectile, SpriteKind.Enemy, function (sprite, otherSprite) {
  391. let edge = GetCollisionEdge(sprite, otherSprite)
  392. let r = randint(1, 100)
  393. if(r > 80 && ballList.length < 25 && liveItems.length < 3) {
  394. let item = new Item(sprite.x, sprite.y, randint(2, 5))
  395. liveItems.push(item)
  396. }
  397. switch(edge)
  398. {
  399. case CollisionEdge.Top:
  400. if(sprite.vy > 0){
  401. sprite.vy = -sprite.vy * 1.05
  402. }
  403. break
  404. case CollisionEdge.Bottom:
  405. if(sprite.vy < 0){
  406. sprite.vy = -sprite.vy * 1.05
  407. }
  408. break
  409. case CollisionEdge.Left:
  410. if(sprite.vx > 0) {
  411. sprite.vx = -sprite.vx * 1.05
  412. }
  413. break
  414. case CollisionEdge.Right:
  415. if(sprite.vx < 0){
  416. sprite.vx = -sprite.vx * 1.05
  417. }
  418. break
  419. }
  420. for(let i = 0; i < BlocksObjects.length; ++i) {
  421. let myBlock = BlocksObjects[i]
  422. if(myBlock.block == otherSprite) {
  423. if(myBlock.BeBreakOut() == true) {
  424. let item = BlocksObjects.removeAt(i)
  425. item.block.destroy()
  426. if(BlocksObjects.length == 0) {
  427. music.powerUp.play()
  428. }
  429. }
  430. break
  431. }
  432. }
  433. })
  434. game.onUpdate(function() {
  435. let background = scene.backgroundImage();
  436. background.fill(0)
  437. for(let i = ballList.length - 1; i >= 0; --i)
  438. {
  439. let pos = ballList[i].GetPos()
  440. if(pos.y > 117) {
  441. let ball = ballList.removeAt(i)
  442. ball.ball.destroy()
  443. }
  444. }
  445. })