-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpancake.lua
1679 lines (1587 loc) · 57.8 KB
/
pancake.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
local pancake = { }
----------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------
---- _ _ ----
---- | | (_) ----
---- __ __ __ _ _ __ ___ ___ | | __ ___ ___ _ __ __ _ _ _ __ ___ ----
---- | _ \ / _ | | _ \ / __| / _ | | |/ / / _ \ / _ \ | _ \ / _ | | | | _ \ / _ \ ----
---- | |_) | | (_| | | | | | | (__ | (_| | | < | __/ | __/ | | | | | (_| | | | | | | | | __/ ----
---- | .__/ \__,_| |_| |_| \___| \__,_| |_|\_\ \___| \___| |_| |_| \__, | |_| |_| |_| \___| ----
---- | | __/ | ----
---- |_| |___/ ----
---- ----
---- BY MIGHTYPANCAKE ----
-- (Filip Król) ----
----------------------------------------------------------------------------------------------------------------
-------------------------------------v.1.1.1(added pancake.addAssets()!)----------------------------------------
--LIBRARIES USED:
local smallfolk = require "libraries/smallfolk" --smallfolk: https://github.com./gvx/Smallfolk
function pancake.init (settings)
--Applying scale filter...
love.graphics.setDefaultFilter( "nearest", "nearest", 1)
--Creating important tables such as objects or images...
pancake.objects = {}
pancake.images = {}
pancake.sounds = {}
pancake.buttons = {}
pancake.timers = {}
pancake.trashbin = {}
pancake.lastID = 0
pancake.cameraFollow = nil
defineLetters()
--Applying other settings...
pancake.debugMode = settings.debugMode or false
--Setting window...
local window = settings.window or {}
window.pixelSize = window.pixelSize or 5
pancake.lastPixelSize = window.pixelSize
local pixelSize = window.pixelSize
window.width = window.width or 64
window.height = window.height or window.width
window.x = window.x or love.graphics.getWidth()/2 - pixelSize*window.width/2
window.y = window.y or love.graphics.getHeight()/2 - pixelSize*window.height/2
window.offsetX = window.offsetX or 0
window.offsetY = window.offsetY or 0
pancake.window = window
pancake.canvas = love.graphics.newCanvas(pancake.window.width*pixelSize, pancake.window.height*pixelSize)
--Setting background...
local background = settings.background or {}
background.r = background.r or 1
background.g = background.g or 1
background.b = background.b or 1
background.a = background.a or 1
pancake.background = background
pancake.meter = settings.meter or 10
local physics = settings.physics or {}
physics.gravityX = physics.gravityX or 0*pancake.meter
physics.gravityY = physics.gravityY or 12*pancake.meter
physics.defaultmaxVelocity = physics.defaultmaxVelocity or 15*pancake.meter --quite fast to be honest
physics.defaultMass = physics.defaultMass or 10 -- 10 is a rough equivalent of a pancake on plate :P
physics.defaultBounciness = physics.defaultBounciness or 1
physics.defaultFriction = physics.defaultFriction or 0.75
physics.airResistance = physics.airResistance or 7 --how many Newtons/pixel should physics apply?
physics.energyLoss = physics.energyLoss or 0
pancake.physics = physics
--End of physics
pancake.os = love.system.getOS( )
pancake.lastdt = 0.001
pancake.smoothRender = settings.smoothRender or false
pancake.target = nil
pancake.targetLock = false
pancake.autoDraw = true
pancake.layerDepth = settings.layerDepth or 0.75
pancake.animations = {}
pancake.screenShake = true
pancake.loadAnimation = {}
pancake.paused = false
if pancake.loadAnimation then
for i = 1, 6 do
pancake.addSound("pancake".. i, "sounds")
end
pancake.paused = true
pancake.addAnimation("pancake", "anim", "images/pancake animation", 200)
local animation = pancake.loadAnimation
animation.frames = 35
animation.frame = 1
animation.duration = 1000
animation.time = 0
animation[1] = pancake.animations.pancake.anim[1]
animation[2] = pancake.animations.pancake.anim[2]
animation[3] = pancake.animations.pancake.anim[1]
animation[4] = pancake.animations.pancake.anim[2]
animation[5] = pancake.animations.pancake.anim[1]
animation[6] = pancake.animations.pancake.anim[2]
animation[7] = pancake.animations.pancake.anim[3]
for i = 4, 30 do
animation[4+i] = pancake.animations.pancake.anim[i]
end
animation[35] = pancake.animations.pancake.anim[20]
end
--local shaderCode = "vec4 effect(vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords){ vec4 texturecolor = Texel(tex, texture_coords); return vec4(1.0,1.0,1.0,0.8)*texturecolor; } vec4 position(mat4 transform_projection, vec4 vertex_position){ return transform_projection*vertex_position; }"
--pancake.shader = love.graphics.newShader(shaderCode)
end
----------------------
--Drawing functions!--
----------------------
function pancake.draw()
--love.graphics.setShader(pancake.shader)
local scale = pancake.window.pixelSize
local window = pancake.window
--Drawing pancake canvas! WITH BORDERS!!
love.graphics.setCanvas(pancake.canvas)
love.graphics.clear()
love.graphics.scale(scale)
drawBackground()
love.graphics.translate(-window.offsetX,-window.offsetY)
if pancake.shake and pancake.shake.mode == "internal" then
love.graphics.translate(pancake.shake.offsetX,pancake.shake.offsetY)
end
if pancake.debugMode then
drawHitboxes()
end
drawObjects()
if pancake.debugMode then
drawNerdData()
love.graphics.scale(1/scale)
drawMoveVectors()
love.graphics.scale(scale)
end
love.graphics.origin()
if pancake.loadAnimation then
drawLoadAnimation()
love.graphics.origin()
end
--Drawing canvas...
love.graphics.setCanvas()
if pancake.autoDraw then
if pancake.shake and pancake.shake.mode == "external" then
love.graphics.translate(pancake.shake.offsetX*scale,pancake.shake.offsetY*scale)
end
love.graphics.draw(pancake.canvas, pancake.window.x, pancake.window.y)
love.graphics.origin()
end
pancake.drawButtons()
if pancake.debugMode then
pancake.drawInfo()
end
end
function drawLoadAnimation()
local animation = pancake.loadAnimation
local scale = pancake.window.pixelSize*pancake.window.height/16
love.graphics.scale(scale)
if not (animation.frame == 35 and animation.time >= 2500) then
love.graphics.setColor(1,1,1,1)
love.graphics.rectangle("fill", 0, 0, 16, 16)
love.graphics.draw(pancake.images[animation[animation.frame]])
end
if animation.frame == 1 then
love.graphics.setColor(0,0,0,1-(animation.time + 100)/animation.duration)
love.graphics.rectangle("fill", 0, 0, 16, 16)
elseif animation.frame == 35 and animation.time <= 2500 then
love.graphics.setColor(0,0,0,(animation.time-1500)/1000)
love.graphics.rectangle("fill", 0, 0, 16, 16)
elseif animation.frame == 35 and animation.time >= 2500 then
love.graphics.setColor(0,0,0,1-(animation.time - 2500)/1000)
love.graphics.rectangle("fill", 0, 0, 16, 16)
end
love.graphics.setColor(1,1,1,1)
end
function drawMoveVectors()
local pixelSize = pancake.window.pixelSize
local scale = scale or pancake.window.pixelSize/6
for i = 1, #pancake.renderedObjects() do
local object = pancake.renderedObjects()[i]
if object.physics then
local valueX = object.velocityX
local valueY = object.velocityY
local x = object.x
local y = object.y
if not pancake.smoothRender then
x = pancake.round(x)
y = pancake.round(y)
end
x = x*pixelSize + object.width*pixelSize/2
y = y*pixelSize + object.height*pixelSize/2
love.graphics.line(x, y, x + valueX*scale,y + valueY*scale)
love.graphics.setColor(0.2,0.2, 1, 1)
x = object.x*pixelSize + object.width*pancake.window.pixelSize/2 + valueX*scale
y = object.y*pixelSize + object.height*pancake.window.pixelSize/2 + valueY*scale
love.graphics.line(x, y, x + object.force.x*scale/3,y + object.force.y*scale/3)
love.graphics.setColor(1,1,1,1)
end
end
end
function pancake.renderedObjects()
local window = pancake.window
local ret = {}
for i = 1, #pancake.objects do
local object = pancake.objects[i]
if pancake.collisionCheck({x = window.offsetX, y = window.offsetY, width = window.width, height = window.height}, object) then
ret[#ret + 1] = object
end
end
return ret
end
function pancake.drawInfo(x, y)
local x = x or pancake.window.x
local y = y or pancake.window.y
love.graphics.translate(x, y)
if pancake.target then
local target = pancake.target
pancake.print("Name: ".. pancake.boolConversion(target.name, target.name, " "), 0,0,3)
pancake.print("X :" .. target.x or " ", 0,16,3)
pancake.print("Y :" .. target.y or " ", 0,32,3)
pressure = {down = pancake.getStat(target, "pressureDown"), up = pancake.getStat(target, "pressureUp"), right = pancake.getStat(target, "pressureRight"), left = pancake.getStat(target, "pressureLeft")}
pancake.print("VX:" .. pancake.getStat(target, "velocityX"), 0,48,3)
pancake.print("VY:" .. pancake.getStat(target, "velocityY"), 0,64,3)
pancake.print("AX:" .. pancake.getStat(target, "accelarityX"), 0,80,3)
pancake.print("AY:" .. pancake.getStat(target, "accelarityY"), 0,96,3)
pancake.print("DOWN surface:" .. pancake.getSurfaceContact(target).down .. " pressure: " .. pressure.down, 0,112,3)
pancake.print("UP surface:" .. pancake.getSurfaceContact(target).up .. " pressure: " .. pressure.up, 0,128,3)
pancake.print("RIGHT surface:" .. pancake.getSurfaceContact(target).right .. " pressure: " .. pressure.right, 0,144,3)
pancake.print("LEFT surface:" .. pancake.getSurfaceContact(target).left .. " pressure: " .. pressure.left, 0,160,3)
pancake.print("Friction: " .. pancake.getStat(target, "friction") or " ", 0,176,3)
if not target.physics then
pancake.print("no physics applied", 0,192,3)
end
end
love.graphics.translate(-x, -y)
end
function pancake.windowToDisplay(x,y, cameraRelative)
local ret
if pancake.smoothRender then
ret = {x = pancake.window.x + pancake.window.pixelSize*(x - pancake.boolConversion(cameraRelative, pancake.window.offsetX,0)), y = pancake.window.y + pancake.window.pixelSize*(y - pancake.boolConversion(cameraRelative,pancake.window.offsetY, 0))}
else
ret = {x = pancake.window.x + pancake.window.pixelSize*(pancake.round(x) - pancake.boolConversion(cameraRelative, pancake.round(pancake.window.offsetX),0)), y = pancake.window.y + pancake.window.pixelSize*(pancake.round(y) - pancake.boolConversion(cameraRelative, pancake.round(pancake.window.offsetY), 0))}
end
return ret
end
function drawBackground()
local background = pancake.background
love.graphics.setColor(background.r, background.g, background.b, background.a)
if background.image then
love.graphics.draw(background.image)
else
love.graphics.rectangle("fill", 0, 0, pancake.window.width, pancake.window.height)
end
love.graphics.setColor(1,1,1,1)
end
function drawObjects()
local scale = pancake.window.pixelSize
local x = 0
local y = 0
local objects = pancake.renderedObjects()
--How many layers there are?
local layers = 1
for i = 1, #objects do
local layer = objects[i].layer or 1
layers = pancake.boolConversion(layer > layers, layer, layers)
end
for l = layers, 1, -1 do
if l == 1 then
love.graphics.setColor(1,1,1,1)
else
love.graphics.setColor(1 - (l-1)*pancake.layerDepth/layers, 1 - (l-1)*pancake.layerDepth/layers, 1 - (l-1)*pancake.layerDepth/layers, 1)
end
for i = 1, #objects do
local object = objects[i]
local layer = object.layer or 1
if l == layer then
if pancake.andCheck(object, {"x","y","image"}) then
x = object.x
y = object.y
if not pancake.smoothRender then
x = pancake.round(x)
y = pancake.round(y)
end
local offsetX = pancake.boolConversion(object.offsetX, object.offsetX, 0)*pancake.boolConversion(object.flippedX, -1, 1)
local offsetY = pancake.boolConversion(object.offsetY, object.offsetY, 0)*pancake.boolConversion(object.flippedY, -1, 1)
love.graphics.draw(pancake.images[object.image], x + offsetX + pancake.boolConversion(object.flippedX, object.width, 0), y + offsetY + pancake.boolConversion(object.flippedY, object.height, 0), 0, pancake.boolConversion(object.flippedX, -1, 1),pancake.boolConversion(object.flippedY, -1, 1))
if object.textured then
local texture = object.texture
for px = 0, math.floor(object.width)/texture.width-1 do
for py = 0, math.floor(object.height)/texture.height-1 do
love.graphics.draw(pancake.images[object.image], x + px*texture.width, y + py*texture.height)
end
end
end
end
end
end
end
end
function pancake.changeAnimation(object, animationName)
local animations = pancake.animations
if animations[object.name] and animations[object.name][animationName] then
if not (object.animation and object.animation.name == animationName) then
local animationTemplate = animations[object.name][animationName]
local animation = {}
animation.name = animationName
animation.frame = 1
animation.frames = animationTemplate.frames
animation.duration = animationTemplate.speed
animation.time = 0
for i = 1, #animationTemplate do
animation[i] = animationTemplate[i]
end
object.animation = animation
end
end
end
function pancake.addAnimation(objectName, animationName, folder, speed)
local speed = speed or 150
local animations = pancake.animations
if not animations[objectName] then
animations[objectName] = {}
end
animations[objectName][animationName] = {}
local animation = animations[objectName][animationName]
local broke = false
if #love.filesystem.getDirectoryItems(folder) > 1 then
for frame = 1, 1000 do
local addedFrame = false
for i = 1, #love.filesystem.getDirectoryItems(folder) do
local filename = love.filesystem.getDirectoryItems(folder)[i]
if filename == objectName.."_"..animationName..frame..".png" then
pancake.addImage(objectName.."_"..animationName..frame,folder)
animation[frame] = objectName.."_"..animationName..frame
addedFrame = true
elseif i == #love.filesystem.getDirectoryItems(folder) and not addedFrame then
broke = true
end
end
if broke then
animation.frames = frame - 1
animation.speed = speed
break
end
end
end
return animation
end
function drawNerdData()
local scale = pancake.window.pixelSize
for i = 1, #pancake.renderedObjects() do
local object = pancake.renderedObjects()[i]
local x = object.x
local y = object.y
if not pancake.smoothRender then
x = pancake.round(x)
y = pancake.round(y)
end
pancake.print(i,x,y, 2/scale)
pancake.print(object.ID, x, y + 10/scale, 2/scale)
end
end
function drawHitboxes()
local objects = pancake.renderedObjects()
for i = 1, #objects do
local object = pancake.renderedObjects()[i]
local x = object.x
local y = object.y
if not pancake.smoothRender then
x = pancake.round(x)
y = pancake.round(y)
end
if pancake.andCheck(object, {"x", "y", "height", "width"}) then
love.graphics.setColor(0.4, 1 ,0.4, 0.3)
love.graphics.rectangle("fill", x, y, object.width, object.height)
end
if object.width and object.height and object.x and object.y then
for i = 0, object.width - 1 do
love.graphics.setColor(1,0,0,0.5)
love.graphics.rectangle("fill", x + i, y + object.height, 1, 1)
love.graphics.setColor(1,0.5,0,0.5)
love.graphics.rectangle("fill", x + i, y - 1, 1, 1)
end
for i = 0, object.height - 1 do
love.graphics.setColor(1,1,0,0.5)
love.graphics.rectangle("fill", x - 1, y + i, 1, 1)
love.graphics.setColor(1,0,1,0.5)
love.graphics.rectangle("fill", x + object.width, y + i, 1, 1)
end
end
end
love.graphics.setColor(1,1,1,1)
end
-- Object functions!
function pancake.addObject(object)
pancake.objects[#pancake.objects + 1] = pancake.assignID(object)
return pancake.objects[#pancake.objects]
end
--Physics functions
function pancake.applyPhysics(object, settings)
local physics = pancake.physics
object.physics = true
local settings = settings or {}
object.mass = settings.mass or physics.defaultMass
object.maxVelocity = settings.maxVelocity or physics.defaultmaxVelocity
object.maxVelocityX = object.maxVelocity
object.maxVelocityY = object.maxVelocity
object.bounciness = settings.bounciness or physics.defaultBounciness
object.velocityX = 0
object.velocityY = 0
object.friction = settings.friction or physics.defaultFriction or 0.8
object.forces = {}
object.force = {x = 0, y = 0}
pancake.addForce(object, {time = "infinite", x = physics.gravityX, y = physics.gravityY, relativeToMass = true})
return object
end
function pancake.getFacingObjects(object)
local step = 0.00001
--down
object.y = object.y + step
local down = pancake.getCollidingObjects(object)
object.y = object.y - step
--up
object.y = object.y - step
local up = pancake.getCollidingObjects(object)
object.y = object.y + step
--left
object.x = object.x - step
local left = pancake.getCollidingObjects(object)
object.x = object.x + step
--right
object.x = object.x + step
local right = pancake.getCollidingObjects(object)
object.x = object.x - step
return {down = down, up = up, left = left, right = right}
end
function pancake.facing(object)
local up = pancake.getSurfaceContact(object).up > 0
local down = pancake.getSurfaceContact(object).down > 0
local right = pancake.getSurfaceContact(object).right > 0
local left = pancake.getSurfaceContact(object).left > 0
return {left = left, up = up, right = right, down = down}
end
function pancake.addForce(object, force) --force is a table of strength; x and y parameters that create a vector and time it should work. For example force = {x = 5, y = 0, time = 1000} will push a body of mass equal to 5 one meter per second squared for 1 seconds
force.x = force.x or 0
force.y = force.y or 0
force.time = force.time or 1000
object.forces[#object.forces + 1] = pancake.assignID(force)
return force
end
function pancake.addTimer(time, mode, func, arguments) --TIME IS IN MS! Mode can be repetetive or single. If single is pick timer will run once and execute func function once, then delete itself. Repetitive basically acts like a timed loop executing func every x seconds
local time = time or 1000
local mode = mode or "single"
local timer = pancake.assignID({duration = time, time = 0, mode = mode, func = func, arguments = arguments})
pancake.timers[#pancake.timers + 1] = timer
return timer
end
-------------------------
--ON UPDATE FINCTIONS----
-------------------------
function pancake.update(dt)
--Handle load animation
if pancake.window.pixelSize ~= pancake.lastPixelSize then
pancake.canvas = love.graphics.newCanvas(pancake.window.width*pancake.window.pixelSize, pancake.window.height*pancake.window.pixelSize)
end
pancake.lastPixelSize = pancake.window.pixelSize
if pancake.loadAnimation then
updateLoadAnimation(dt)
end
local dt = pancake.boolConversion(pancake.paused, 0, dt)
pancake.lastdt = pancake.boolConversion(dt == 0, pancake.lastdt, dt)
updateTimers(dt)
--APPLY PHYSICS
pancake.updateObjects(dt)
updateForces(dt) --changes velocity!!!
--END OF PHYSICS
switchTarget(love.mouse.getX(), love.mouse.getY())
cameraFollowObjects()
--Handle scren shake
updateScreenShake(dt)
--THIS SHOULD ALWAYS BE LAST
emptyTrash()
end
function updateLoadAnimation(dt)
local animation = pancake.loadAnimation
animation.time = animation.time + dt*1000
if animation.time >= animation.duration then
animation.time = animation.time - animation.duration
animation.frame = animation.frame + 1
local frame = animation.frame
if frame == 2 then
pancake.playSound("pancake1")
animation.duration = 120
elseif frame == 3 then
pancake.playSound("pancake2")
elseif frame == 4 then
pancake.playSound("pancake1")
elseif frame == 5 then
pancake.playSound("pancake2")
elseif frame == 6 then
pancake.playSound("pancake1")
elseif frame == 7 then
pancake.playSound("pancake2")
elseif frame == 9 then
animation.duration = 80
pancake.playSound("pancake3")
elseif frame == 12 then
animation.duration = 400
elseif frame == 13 then
animation.duration = 85
elseif frame == 14 then
pancake.playSound("pancake4")
elseif frame == 21 then
animation.duration = 800
elseif frame == 22 then
animation.duration = 80
pancake.playSound("pancake5")
elseif frame == 24 then
animation.duration = 800
elseif frame == 25 then
animation.duration = 100
pancake.playSound("pancake6")
elseif frame == 35 then
animation.duration = 3500
end
if animation.frame > animation.frames then
pancake.loadAnimation = nil
pancake.paused = false
pancake.onLoad()
end
end
end
function updateScreenShake(dt)
if not pancake.screenShake then
pancake.shake = nil
end
local shake = pancake.shake
if shake then
shake.time = shake.time + dt*1000
if shake.time >= shake.duration then
shake.time = shake.time - shake.duration
shake.iteration = shake.iteration + 1
shake.axis = pancake.opposite(shake.axis)
if shake.iteration%2 == 0 then
shake.direction = -shake.direction
end
shake["offset" .. string.upper(shake.axis)] = shake.direction*math.random(0, shake.amplitude)
shake["offset" .. string.upper(pancake.opposite(shake.axis))] = 0
end
if shake.iteration > shake.iterations then
pancake.shake = nil
end
end
end
function cameraFollowObjects()
local object = pancake.cameraFollow
local window = pancake.window
if object then
if pancake.smoothRender then
window.offsetX = object.x - window.width/2 + object.width/2
window.offsetY = object.y - window.height/2 + object.height/2
else
window.offsetX = pancake.round(object.x - window.width/2 + math.floor(object.width/2))
window.offsetY = pancake.round(object.y - window.height/2 + math.floor(object.height/2))
end
else
window.offsetX = 0
window.offsetY = 0
end
end
function pancake.getRoadTime(s, v, a)
local ret
local del = pancake.delta(1/2*a, v, -s)
local a = a or 0
if a == 0 then
ret = s/v
elseif del >= 0 then
ret = (-v+math.sqrt(del))/a --This the time necessary to travel s with speed of v and acceleraty of a
end
return ret
end
function pancake.updateObjects(dt)
local objects = pancake.objects
local collisions = {}
local colls = {}
pancake.collidingObjects = {}
pancake.physicObjects = {}
for i = 1, #objects do
local object = objects[i]
checkForOverlap(object)
object.pressureDown = nil
object.pressureUp = nil
object.pressureLeft = nil
object.pressureRight = nil
object.collidedWith = nil
if object.physics then
pancake.physicObjects[#pancake.physicObjects + 1] = object
object.force.x = 0
object.force.y = 0
end
if object.colliding == true then
pancake.collidingObjects[#pancake.collidingObjects + 1] = object
end
end
--Moving objects with remaining time!
for i = 1, #objects do
local object = objects[i]
if object.animation then
local animation = object.animation
animation.time = animation.time + dt*1000
if animation.time >= animation.duration then
animation.frame = animation.frame + 1
animation.time = animation.time - animation.duration
if animation.frame > animation.frames then
animation.frame = 1
end
end
object.image = animation[animation.frame]
end
if object.physics then
local t = dt
local ax = pancake.getStat(object, "accelarityX")
local vx = pancake.getStat(object, "velocityX")
local ay = pancake.getStat(object, "accelarityY")
local vy = pancake.getStat(object, "velocityY")
colls = pancake.move(object, vx*t + 1/2*ax*t*t, vy*t + 1/2*ay*t*t)
if colls and colls[1] then
for i = 1, #colls do
collisions[#collisions + 1] = colls[i]
end
end
end
end
if collisions[1] then
for i = 1, #collisions do
local collision = collisions[i]
pancake.applyForce(collision.object, collision.force, dt)
end
end
end
function checkForOverlap(object)
local dt = pancake.lastdt
local objects = pancake.objects
for i = 1, #objects do
local object2 = objects[i]
if object2 ~= object and pancake.collisionCheck(object, object2) then
if pancake.onOverlap then
pancake.onOverlap(object, object2, dt)
end
end
end
end
function pancake.delta(a,b,c)
return b*b - (4*a*c)
end
function pancake.getPressure(object, directionName)
local force = 0
if object.physics then
if directionName == "down" then
force = pancake.getStat(object, "forceY") + object.velocityY*object.mass/pancake.lastdt
local objects = pancake.getFacingObjects(object)[pancake.opposite(directionName)]
if #objects > 0 then
for i = 1,#objects do
local press = pancake.getStat(objects[i], "pressure" .. pancake.intoCaps(directionName))
force = force + pancake.boolConversion(press >= 0, press, 0)/#objects/#pancake.getFacingObjects(objects[i])[directionName]
end
end
elseif directionName == "up" then
force = -pancake.getStat(object, "forceY") - object.velocityY*object.mass/pancake.lastdt
local objects = pancake.getFacingObjects(object)[pancake.opposite(directionName)]
if #objects > 0 then
for i = 1,#objects do
local press = pancake.getStat(objects[i], "pressure" .. pancake.intoCaps(directionName))
force = force + pancake.boolConversion(press <= 0, press, 0)/#objects/#pancake.getFacingObjects(objects[i])[directionName]
end
end
--X AXIS
elseif directionName == "right" then
force = pancake.getStat(object, "forceX") + object.velocityX*object.mass/pancake.lastdt
local objects = pancake.getFacingObjects(object)[pancake.opposite(directionName)]
if #objects > 0 then
for i = 1,#objects do
local press = pancake.getStat(objects[i], "pressure" .. pancake.intoCaps(directionName))
force = force + pancake.boolConversion(press >= 0, press, 0)/#objects/#pancake.getFacingObjects(objects[i])[directionName]
end
end
elseif directionName == "left" then
force = -pancake.getStat(object, "forceX") - object.velocityX*object.mass/pancake.lastdt
local objects = pancake.getFacingObjects(object)[pancake.opposite(directionName)]
if #objects > 0 then
for i = 1,#objects do
local press = pancake.getStat(objects[i], "pressure" .. pancake.intoCaps(directionName))
force = force + pancake.boolConversion(press <= 0, press, 0)/#objects/#pancake.getFacingObjects(objects[i])[directionName]
end
end
end
end
force = pancake.boolConversion(force <= 0, 0, force)
object["pressure" .. pancake.intoCaps(directionName)] = force
return force
end
function pancake.getStat(object, stat)
local ret = object[stat] or 0
if stat == "forceX" then
if object.forces and object.forces[1] then
for i = 1, #object.forces do
local force = object.forces[i]
local mr = pancake.boolConversion(force.relativeToMass, object.mass, 1)
ret = ret + force.x*mr
end
end
elseif stat == "forceY" then
if object.forces and object.forces[1] then
for i = 1, #object.forces do
local force = object.forces[i]
local mr = pancake.boolConversion(force.relativeToMass, object.mass, 1)
ret = ret + force.y*mr
end
end
elseif stat == "mass" then
ret = object.mass or 1
elseif stat == "velocityX" or stat == "velocityY" then
ret = object[stat] or 0
elseif stat == "bounciness" then
ret = object[stat] or 1
elseif stat == "friction" then
ret = object[stat] or 1
elseif stat == "accelarityX" then
ret = pancake.getStat(object, "forceX")/pancake.getStat(object, "mass")
elseif stat == "accelarityY" then
ret = pancake.getStat(object, "forceY")/pancake.getStat(object, "mass")
elseif stat == "directionX" then
ret = pancake.boolConversion(pancake.getStat(object, "velocityX") == 0, 0, pancake.getStat(object, "velocityX")/math.abs(pancake.getStat(object, "velocityX")))
elseif stat == "directionY" then
ret = pancake.boolConversion(pancake.getStat(object, "velocityY") == 0, 0, pancake.getStat(object, "velocityY")/math.abs(pancake.getStat(object, "velocityY")))
elseif stat == "momentumX" then
ret = math.abs(pancake.getStat(object, "velocityX")*pancake.getStat(object, "mass"))
elseif stat == "momentumY" then
ret = math.abs(pancake.getStat(object, "velocityY")*pancake.getStat(object, "mass"))
elseif stat == "pressureDown" then
ret = object.pressureDown or pancake.getPressure(object, "down")
elseif stat == "pressureUp" then
ret = object.pressureUp or pancake.getPressure(object, "up")
elseif stat == "pressureLeft" then
ret = object.pressureLeft or pancake.getPressure(object, "left")
elseif stat == "pressureRight" then
ret = object.pressureRight or pancake.getPressure(object, "right")
end
return ret
end
function pancake.applyForce(object, force, dt, unsaved)
local dt = dt or pancake.lastdt
local unsaved = unsaved or false
force.x = force.x or 0
force.y = force.y or 0
if object.physics then
local mr = pancake.boolConversion(force.relativeToMass, object.mass, 1)
object.velocityX = object.velocityX + force.x*dt/object.mass*mr
object.velocityY = object.velocityY + force.y*dt/object.mass*mr
if not unsaved then
object.force.x = object.force.x + force.x/object.mass*mr
object.force.y = object.force.y + force.y/object.mass*mr
end
end
end
function updateForces(dt)
local deleteThese
local objects = pancake.physicObjects
for i = 1, #objects do
local object = objects[i]
if object.physics then
deleteThese = {}
local forces = object.forces
if forces[1] then
for f = 1, #forces do
local force = forces[f]
local finaldt = dt
if force.time ~= "infinite" then
force.time = force.time - dt*1000
if force.time <= 0 then
finaldt = dt + force.time/1000
deleteThese[#deleteThese + 1] = force.ID
end
end
pancake.applyForce(object, force, finaldt)
end
--Cap to max velocity and max velocity on each axis
local velocityCap = pancake.boolConversion(object.maxVelocity <= object.maxVelocityX, object.maxVelocity, object.maxVelocityX)
if math.abs(object.velocityX) > velocityCap then
object.velocityX = object.velocityX - pancake.sigma(object.velocityX)*(math.abs(object.velocityX) - velocityCap)
end
velocityCap = pancake.boolConversion(object.maxVelocity <= object.maxVelocityY, object.maxVelocity, object.maxVelocityY)
if math.abs(object.velocityY) > velocityCap then
object.velocityY = object.velocityY - pancake.sigma(object.velocityY)*(math.abs(object.velocityY) - velocityCap)
end
if deleteThese[1] then
for u = 1, #deleteThese do
pancake.smartDelete(forces, deleteThese[u], "ID")
end
end
end
end
end
end
function collide(object1, objects, axis, direction, sc, oa) --sc is a short for simultanously collisions it indicates how many simultanious collisions happen
local collisions = {}
local originalCord = object1[axis]
local dt = pancake.lastdt
local axisParam = pancake.boolConversion(axis == "x", "width", "height")
local forceSum = {x = 0, y = 0}
local object2 = objects[1]
local ret = {}
local destination = pancake.boolConversion(direction == 1, object2[axis] - object1[axisParam], object2[axis] + object2[axisParam])
local distance = math.abs(object1[axis] - destination)
local biggestDistance = distance
for i = 1, #objects do
object2 = objects[i]
destination = pancake.boolConversion(direction == 1, object2[axis] - object1[axisParam], object2[axis] + object2[axisParam])
distance = math.abs(object1[axis] - destination)
if biggestDistance < distance then
ret = {object2}
biggestDistance = distance
elseif biggestDistance == distance then
ret[#ret+1] = object2
end
end
local objects = ret
local object2 = objects[1]
sc = #objects
object1[axis] = pancake.boolConversion(direction == 1, object2[axis] - object1[axisParam], object2[axis] + object2[axisParam])
if pancake.isObjectColliding(object1) then
object1[axis] = oa
end
--call custom collision function!
for i = 1, #objects do
object2 = objects[i]
local ret = true
if not didTheyCollide(object1, object2) then
if pancake.onCollision then
ret = pancake.onCollision(object1, object2, axis, direction, sc)
if ret == nil then
ret = true
end
end
if ret then
local force2 = pancake.getCollisionForces(object1, object2, axis, direction, sc)[2]
collisions[#collisions + 1] = {object = object2, force = force2}
forceSum.x = forceSum.x + pancake.getCollisionForces(object1, object2, axis, direction, sc)[1].x
forceSum.y = forceSum.y + pancake.getCollisionForces(object1, object2, axis, direction, sc)[1].y
end
if not object2.collidedWith then
object2.collidedWith = {}
end
object2.collidedWith[object1.ID] = true
end
end
local force1 = {}
force1 = forceSum
collisions[#collisions + 1] = {object = object1, force = force1}
return collisions
end
function didTheyCollide(object1, object2)
local ret = false
if object1.collidedWith then
if object1.collidedWith[object2.ID] then
ret = true
end
end
return ret
end
function pancake.getCollisionForces(object1, object2, axis, direction, sc)
local dt = pancake.lastdt
local sc = sc or 1
local directionName = pancake.getDirectionName(axis, direction)
local physics = pancake.physics
local bounciness1 = pancake.getStat(object1, "bounciness")
local bounciness2 = pancake.getStat(object2, "bounciness")
local pressure1 = pancake.getStat(object1, "pressure" .. pancake.intoCaps(directionName))
local pressure2 = pancake.getStat(object2, "pressure" .. pancake.intoCaps(pancake.opposite(directionName)))
local pressureSum = pressure1 + pressure2
local force1 = {x = 0, y = 0}
force1[axis] = -direction*pressureSum*(bounciness1-bounciness2 + 1)*(1-physics.energyLoss)/sc
local force2 = {x = 0, y = 0}
force2[axis] = direction*pressureSum*(bounciness2-bounciness1 + 1)*(1-physics.energyLoss)/sc
--Calculate friction force...
frictionAxis = pancake.opposite(axis)
local friction1 = 0
local friction2 = 0
local maxFriction1 = -pancake.getStat(object1, "velocity" .. string.upper(frictionAxis))*pancake.getStat(object1, "mass")/dt/sc
friction1 = -pancake.getStat(object1,"direction" .. string.upper(frictionAxis))*pressureSum*(pancake.getStat(object1, "friction")+pancake.getStat(object2, "friction"))/2/sc
if math.abs(friction1) > math.abs(maxFriction1) then
friction1 = maxFriction1
end
force1[frictionAxis] = friction1
force2[frictionAxis] = -friction1
local ret = {}
ret[1] = force1
ret[2] = force2
return ret
end
function pancake.opposite(value)
local ret
if value == "x" then
ret = "y"
elseif value == "y" then
ret = "x"
elseif value == "down" then
ret = "up"
elseif value == "up" then
ret = "down"
elseif value == "left" then
ret = "right"
elseif value == "right" then
ret = "left"
end
return ret
end
function updateTimers(dt)
local timers = pancake.timers
if timers[1] then
for i = 1, #timers do
local timer = timers[i]
timer.time = timer.time + dt*1000
if timer.time >= timer.duration then
if timer.func then
timer.func(timer.arguments)
end
if timer.mode == "single" then
pancake.trash(pancake.timers, timer.ID, "ID")
elseif timer.mode == "repetetive" then
timer.time = timer.time - timer.duration
end
end
end
end
end
function collideMultiple(object, axis, direction, oa)
local ret = {}
if pancake.isObjectColliding(object) then
local objects = pancake.getCollidingObjects(object)
ret = collide(object, objects, axis, direction, #objects, oa)
end
return ret
end
function pancake.move(object, x, y)
local collisions = {}
local x = x or 0
local y = y or 0
local b = {}
b.x = false
b.y = false
local o = {}
o.x = x
o.y = y
local s = {}
s.x = pancake.sigma(x)
s.y = pancake.sigma(y)
local a = {}
a.x = math.floor(math.abs(x))
a.y = math.floor(math.abs(y))
local p = {}
p.x = a.x
p.y = a.x